Source file : zip-headers.adb
1 -- Legal licensing note:
2
3 -- Copyright (c) 2000 .. 2022 Gautier de Montmollin
4 -- SWITZERLAND
5
6 -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 -- of this software and associated documentation files (the "Software"), to deal
8 -- in the Software without restriction, including without limitation the rights
9 -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 -- copies of the Software, and to permit persons to whom the Software is
11 -- furnished to do so, subject to the following conditions:
12
13 -- The above copyright notice and this permission notice shall be included in
14 -- all copies or substantial portions of the Software.
15
16 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 -- THE SOFTWARE.
23
24 -- NB: this is the MIT License, as found on the site
25 -- http://www.opensource.org/licenses/mit-license.php
26
27 package body Zip.Headers is
28
29 -----------------------------------------------------------
30 -- Byte array <-> various integers, with Intel endianess --
31 -----------------------------------------------------------
32
33 -- Get numbers with correct trucmuche endian, to ensure
34 -- correct header loading on some non-Intel machines
35
36 generic
37 type Number is mod <>; -- range <> in Ada83 version (fake Interfaces)
38 function Intel_x86_number (b : Byte_Buffer) return Number;
39
40 function Intel_x86_number (b : Byte_Buffer) return Number is
41 n : Number := 0;
42 begin
43 for i in reverse b'Range loop
44 n := n * 256 + Number (b (i));
45 end loop;
46 return n;
47 end Intel_x86_number;
48
49 function Intel_nb is new Intel_x86_number (Unsigned_16);
50 function Intel_nb is new Intel_x86_number (Unsigned_32);
51 function Intel_nb is new Intel_x86_number (Unsigned_64);
52
53 -- Put numbers with correct endianess as bytes
54
55 generic
56 type Number is mod <>; -- range <> in Ada83 version (fake Interfaces)
57 size : Positive;
58 function Intel_x86_buffer (n : Number) return Byte_Buffer;
59
60 function Intel_x86_buffer (n : Number) return Byte_Buffer is
61 b : Byte_Buffer (1 .. size);
62 m : Number := n;
63 begin
64 for i in b'Range loop
65 b (i) := Unsigned_8 (m and 255);
66 m := m / 256;
67 end loop;
68 return b;
69 end Intel_x86_buffer;
70
71 function Intel_bf is new Intel_x86_buffer (Unsigned_16, 2);
72 function Intel_bf is new Intel_x86_buffer (Unsigned_32, 4);
73 function Intel_bf is new Intel_x86_buffer (Unsigned_64, 8);
74
75 -------------------
76 -- PK signatures --
77 -------------------
78
79 function PK_signature (buf : Byte_Buffer; code_1, code_2 : Unsigned_8) return Boolean is
80 begin
81 return buf (buf'First .. buf'First + 3) = (16#50#, 16#4B#, code_1, code_2);
82 -- PK12, PK34, ...
83 end PK_signature;
84
85 procedure PK_signature (buf : in out Byte_Buffer; code_1, code_2 : Unsigned_8) is
86 begin
87 buf (1 .. 4) := (16#50#, 16#4B#, code_1, code_2); -- PK12, PK34, ...
88 end PK_signature;
89
90 ------------------------------------------------------------------
91 -- PKZIP data descriptor, after streamed compressed data - PK78 --
92 ------------------------------------------------------------------
93
94 procedure Copy_and_Check
95 (buffer : in Byte_Buffer;
96 the_data_desc : out Data_Descriptor)
97 is
98 begin
99 if not PK_signature (buffer, 7, 8) then
100 raise bad_data_descriptor;
101 end if;
102
103 the_data_desc.crc_32 := Intel_nb (buffer (5 .. 8));
104 the_data_desc.compressed_size := Intel_nb (buffer (9 .. 12));
105 the_data_desc.uncompressed_size := Intel_nb (buffer (13 .. 16));
106
107 end Copy_and_Check;
108
109 procedure Read_and_Check
110 (stream : in out Root_Zipstream_Type'Class;
111 the_data_desc : out Data_Descriptor)
112 is
113 ddb : Byte_Buffer (1 .. 16);
114 begin
115 Block_Read (stream, ddb);
116 Copy_and_Check (ddb, the_data_desc);
117 end Read_and_Check;
118
119 procedure Write
120 (stream : in out Root_Zipstream_Type'Class;
121 the_data_desc : in Data_Descriptor)
122 is
123 ddb : Byte_Buffer (1 .. 16);
124 begin
125 PK_signature (ddb, 7, 8);
126
127 ddb (5 .. 8) := Intel_bf (the_data_desc.crc_32);
128 ddb (9 .. 12) := Intel_bf (the_data_desc.compressed_size);
129 ddb (13 .. 16) := Intel_bf (the_data_desc.uncompressed_size);
130
131 Block_Write (stream, ddb);
132 end Write;
133
134 -------------------------------------------------------
135 -- PKZIP file header, as in central directory - PK12 --
136 -------------------------------------------------------
137 procedure Read_and_Check
138 (stream : in out Root_Zipstream_Type'Class;
139 header : out Central_File_Header)
140 is
141 chb : Byte_Buffer (1 .. 46);
142 begin
143 Block_Read (stream, chb);
144
145 if not PK_signature (chb, 1, 2) then
146 raise bad_central_header;
147 end if;
148
149 header.made_by_version := Intel_nb (chb (5 .. 6));
150 header.short_info.needed_extract_version := Intel_nb (chb (7 .. 8));
151 header.short_info.bit_flag := Intel_nb (chb (9 .. 10));
152 header.short_info.zip_type := Intel_nb (chb (11 .. 12));
153 header.short_info.file_timedate :=
154 Zip_Streams.Calendar.Convert (Unsigned_32'(Intel_nb (chb (13 .. 16))));
155 header.short_info.dd.crc_32 := Intel_nb (chb (17 .. 20));
156 header.short_info.dd.compressed_size := Intel_nb (chb (21 .. 24));
157 header.short_info.dd.uncompressed_size := Intel_nb (chb (25 .. 28));
158 header.short_info.filename_length := Intel_nb (chb (29 .. 30));
159 header.short_info.extra_field_length := Intel_nb (chb (31 .. 32));
160 header.comment_length := Intel_nb (chb (33 .. 34));
161 header.disk_number_start := Intel_nb (chb (35 .. 36));
162 header.internal_attributes := Intel_nb (chb (37 .. 38));
163 header.external_attributes := Intel_nb (chb (39 .. 42));
164 header.local_header_offset := Intel_nb (chb (43 .. 46));
165
166 end Read_and_Check;
167
168 procedure Write
169 (stream : in out Root_Zipstream_Type'Class;
170 header : in Central_File_Header)
171 is
172 chb : Byte_Buffer (1 .. 46);
173 begin
174 PK_signature (chb, 1, 2);
175
176 chb (5 .. 6) := Intel_bf (header.made_by_version);
177 chb (7 .. 8) := Intel_bf (header.short_info.needed_extract_version);
178 chb (9 .. 10) := Intel_bf (header.short_info.bit_flag);
179 chb (11 .. 12) := Intel_bf (header.short_info.zip_type);
180 chb (13 .. 16) := Intel_bf (Zip_Streams.Calendar.Convert (
181 header.short_info.file_timedate)
182 );
183 chb (17 .. 20) := Intel_bf (header.short_info.dd.crc_32);
184 chb (21 .. 24) := Intel_bf (Unsigned_32 (header.short_info.dd.compressed_size));
185 chb (25 .. 28) := Intel_bf (Unsigned_32 (header.short_info.dd.uncompressed_size));
186 chb (29 .. 30) := Intel_bf (header.short_info.filename_length);
187 chb (31 .. 32) := Intel_bf (header.short_info.extra_field_length);
188 chb (33 .. 34) := Intel_bf (header.comment_length);
189 chb (35 .. 36) := Intel_bf (header.disk_number_start);
190 chb (37 .. 38) := Intel_bf (header.internal_attributes);
191 chb (39 .. 42) := Intel_bf (header.external_attributes);
192 chb (43 .. 46) := Intel_bf (Unsigned_32 (header.local_header_offset));
193
194 Block_Write (stream, chb);
195 end Write;
196
197 function Needs_Local_Zip_64_Header_Extension
198 (header : Local_File_Header;
199 offset : Unsigned_64) -- Not part of the Zip32 header but of the Zip64 one...
200 return Boolean
201 is
202 do_we_want_always_zip64 : constant Boolean := False;
203 -- ^ True: Force Zip64 on all entries & central directory, for test purposes
204 -- False: Zip64 is used only when needed
205 begin
206 return do_we_want_always_zip64 or
207 header.dd.compressed_size >= 16#FFFF_FFFF# or
208 header.dd.uncompressed_size >= 16#FFFF_FFFF# or
209 offset >= 16#FFFF_FFFF#;
210 end Needs_Local_Zip_64_Header_Extension;
211
212 -----------------------------------------------------------------------
213 -- PKZIP local file header, in front of every file in archive - PK34 --
214 -----------------------------------------------------------------------
215 procedure Read_and_Check
216 (stream : in out Root_Zipstream_Type'Class;
217 header : out Local_File_Header)
218 is
219 lhb : Byte_Buffer (1 .. local_header_length);
220 u32 : Unsigned_32;
221 begin
222 Block_Read (stream, lhb);
223
224 if not PK_signature (lhb, 3, 4) then
225 raise bad_local_header;
226 end if;
227
228 header.needed_extract_version := Intel_nb (lhb (5 .. 6));
229 header.bit_flag := Intel_nb (lhb (7 .. 8));
230 header.zip_type := Intel_nb (lhb (9 .. 10));
231 header.file_timedate := Zip_Streams.Calendar.Convert (Unsigned_32'(
232 Intel_nb (lhb (11 .. 14))
233 ));
234 header.dd.crc_32 := Intel_nb (lhb (15 .. 18));
235 u32 := Intel_nb (lhb (19 .. 22));
236 header.dd.compressed_size := Unsigned_64 (u32);
237 u32 := Intel_nb (lhb (23 .. 26));
238 header.dd.uncompressed_size := Unsigned_64 (u32);
239 header.filename_length := Intel_nb (lhb (27 .. 28));
240 header.extra_field_length := Intel_nb (lhb (29 .. 30));
241
242 end Read_and_Check;
243
244 procedure Write
245 (stream : in out Root_Zipstream_Type'Class;
246 header : in Local_File_Header;
247 extra_field_policy : in Extra_Field_Policy_Kind)
248 is
249 lhb : Byte_Buffer (1 .. local_header_length);
250 extra_length : Unsigned_16;
251 begin
252 PK_signature (lhb, 3, 4);
253
254 lhb (5 .. 6) := Intel_bf (header.needed_extract_version);
255 lhb (7 .. 8) := Intel_bf (header.bit_flag);
256 lhb (9 .. 10) := Intel_bf (header.zip_type);
257 lhb (11 .. 14) := Intel_bf (Zip_Streams.Calendar.Convert (header.file_timedate));
258 lhb (15 .. 18) := Intel_bf (header.dd.crc_32);
259 if extra_field_policy = force_zip_64 then
260 lhb (19 .. 22) := (255, 255, 255, 255);
261 lhb (23 .. 26) := (255, 255, 255, 255);
262 else
263 lhb (19 .. 22) := Intel_bf (Unsigned_32 (header.dd.compressed_size));
264 lhb (23 .. 26) := Intel_bf (Unsigned_32 (header.dd.uncompressed_size));
265 end if;
266 lhb (27 .. 28) := Intel_bf (header.filename_length);
267
268 case extra_field_policy is
269 when from_header => extra_length := header.extra_field_length;
270 when force_empty => extra_length := 0;
271 when force_zip_64 => extra_length := local_header_extension_short_length;
272 end case;
273 lhb (29 .. 30) := Intel_bf (extra_length);
274
275 Block_Write (stream, lhb);
276 end Write;
277
278 procedure Read_and_Check
279 (stream : in out Root_Zipstream_Type'Class;
280 header : out Local_File_Header_Extension)
281 is
282 lhb_1 : Byte_Buffer (1 .. 4);
283 lhb_2 : Byte_Buffer (5 .. local_header_extension_length);
284 begin
285 Block_Read (stream, lhb_1);
286
287 header.tag := Intel_nb (lhb_1 (1 .. 2));
288 header.size := Intel_nb (lhb_1 (3 .. 4));
289 if header.tag /= local_header_extension_tag then
290 return; -- It's another kind of extra field.
291 end if;
292 if header.size < 8 then
293 raise bad_local_header with "Zip64 extra field bytes < 8";
294 end if;
295
296 Block_Read (stream, lhb_2);
297 header.value_64 (1) := Intel_nb (lhb_2 (5 .. 12));
298 header.value_64 (2) := Intel_nb (lhb_2 (13 .. 20));
299 header.value_64 (3) := Intel_nb (lhb_2 (21 .. 28));
300
301 end Read_and_Check;
302
303 procedure Interpret
304 (header : in Local_File_Header_Extension;
305 uncompressed_size : in out Unsigned_64;
306 compressed_size : in out Unsigned_64;
307 offset : in out Unsigned_64)
308 is
309 counter : Natural := 0;
310 begin
311 if header.tag /= local_header_extension_tag then
312 return; -- It's another kind of extra field.
313 end if;
314 --
315 -- All fields are optional - an unusual feature...
316 --
317 if uncompressed_size = 16#FFFF_FFFF# then
318 counter := counter + 1;
319 uncompressed_size := header.value_64 (counter);
320 end if;
321 if compressed_size = 16#FFFF_FFFF# then
322 counter := counter + 1;
323 compressed_size := header.value_64 (counter);
324 end if;
325 if offset = 16#FFFF_FFFF# then
326 counter := counter + 1;
327 offset := header.value_64 (counter);
328 end if;
329 if counter * 8 > Natural (header.size) then
330 raise bad_local_header
331 with "Zip64 extra field bytes: invalid size:" & header.size'Image &
332 ", needed:" & Integer'Image (counter * 8);
333 end if;
334 end Interpret;
335
336 procedure Write
337 (stream : in out Root_Zipstream_Type'Class;
338 header : in Local_File_Header_Extension;
339 short : in Boolean)
340 is
341 lhb : Byte_Buffer (1 .. local_header_extension_length);
342 begin
343 lhb (1 .. 2) := Intel_bf (header.tag);
344 lhb (3 .. 4) := Intel_bf (header.size);
345 lhb (5 .. 12) := Intel_bf (header.value_64 (1));
346 lhb (13 .. 20) := Intel_bf (header.value_64 (2));
347 lhb (21 .. 28) := Intel_bf (header.value_64 (3));
348 if short then
349 pragma Assert (header.size = local_header_extension_short_length - 4);
350 Block_Write (stream, lhb (1 .. local_header_extension_short_length));
351 else
352 pragma Assert (header.size = local_header_extension_length - 4);
353 Block_Write (stream, lhb);
354 end if;
355 end Write;
356
357 -------------------------------------------
358 -- PKZIP end-of-central-directory - PK56 --
359 -------------------------------------------
360 procedure Copy_and_Check
361 (buffer : in Byte_Buffer;
362 the_end : out End_of_Central_Dir)
363 is
364 o : constant Integer := buffer'First - 1;
365 begin
366 if not PK_signature (buffer, 5, 6) then
367 raise bad_end;
368 end if;
369
370 the_end.disknum := Intel_nb (buffer (o + 5 .. o + 6));
371 the_end.disknum_with_start := Intel_nb (buffer (o + 7 .. o + 8));
372 the_end.disk_total_entries := Intel_nb (buffer (o + 9 .. o + 10));
373 the_end.total_entries := Intel_nb (buffer (o + 11 .. o + 12));
374 the_end.central_dir_size := Intel_nb (buffer (o + 13 .. o + 16));
375 the_end.central_dir_offset := Intel_nb (buffer (o + 17 .. o + 20));
376 the_end.main_comment_length := Intel_nb (buffer (o + 21 .. o + 22));
377
378 end Copy_and_Check;
379
380 procedure Read_and_Check
381 (stream : in out Root_Zipstream_Type'Class;
382 the_end : out End_of_Central_Dir)
383 is
384 eb : Byte_Buffer (1 .. 22);
385 begin
386 Block_Read (stream, eb);
387 Copy_and_Check (eb, the_end);
388 end Read_and_Check;
389
390 procedure Load
391 (stream : in out Root_Zipstream_Type'Class;
392 the_end : out End_of_Central_Dir)
393 is
394 min_end_start : ZS_Index_Type; -- min_end_start >= 1
395 max_comment : constant := 65_535;
396 -- In appnote.txt :
397 -- .ZIP file comment length 2 bytes
398 end_64_loc : Zip64_End_of_Central_Dir_Locator;
399 end_64 : Zip64_End_of_Central_Dir;
400 found : Boolean;
401 function Is_64 return Boolean is
402 begin
403 return the_end.total_entries = 16#FFFF# or
404 the_end.central_dir_size = 16#FFFF_FFFF# or
405 the_end.central_dir_offset = 16#FFFF_FFFF#;
406 end Is_64;
407 begin
408 if Size (stream) < 22 then
409 raise bad_end;
410 end if;
411 -- 20-Jun-2001: abandon search below min_end_start.
412 if Size (stream) <= max_comment then
413 min_end_start := 1;
414 else
415 min_end_start := Size (stream) - max_comment;
416 end if;
417 Set_Index (stream, min_end_start);
418 declare
419 -- We copy a large chunk of the zip stream's tail into a buffer.
420 large_buffer : Byte_Buffer (0 .. Natural (Size (stream) - min_end_start));
421 ilb : Integer;
422 x : ZS_Size_Type;
423 begin
424 found := False;
425 Block_Read (stream, large_buffer);
426 for i in reverse min_end_start .. Size (stream) - 21 loop
427 -- Yes, we must _search_ for the header...
428 -- because PKWARE put a variable-size comment _after_ it 8-(
429 ilb := Integer (i - min_end_start);
430 if PK_signature (large_buffer (ilb .. ilb + 3), 5, 6) then
431 Copy_and_Check (large_buffer (ilb .. ilb + 21), the_end);
432 if Is_64 then
433 found := True;
434 exit;
435 end if;
436 -- At this point, the buffer was successfully read, the_end is
437 -- is set with its standard contents.
438 --
439 -- This is the *real* position of the end-of-central-directory block, to begin with:
440 x := i;
441 -- We subtract the *theoretical* (stored) position of the end-of-central-directory.
442 -- The theoretical position is equal to central_dir_offset + central_dir_size.
443 -- The theoretical position should be smaller or equal than the real position -
444 -- unless the archive is corrupted.
445 -- We do it step by step, because ZS_Size_Type was modular until rev. 644.
446 -- Now it's a signed 64 bits, but we don't want to change anything again...
447 --
448 x := x - 1; -- i >= 1, so no dragons here. The "- 1" is for adapting from the 1-based Ada index.
449 exit when ZS_Size_Type (the_end.central_dir_offset) > x; -- fuzzy value, will trigger bad_end
450 x := x - ZS_Size_Type (the_end.central_dir_offset);
451 exit when ZS_Size_Type (the_end.central_dir_size) > x; -- fuzzy value, will trigger bad_end
452 x := x - ZS_Size_Type (the_end.central_dir_size);
453 -- Now, x is the difference : real - theoretical.
454 -- x > 0 if the archive was appended to another file (typically an executable
455 -- for self-extraction purposes).
456 -- x = 0 if this is a "pure" Zip archive.
457 the_end.offset_shifting := x;
458 Set_Index (stream, i + 22);
459 found := True;
460 exit;
461 end if;
462 end loop;
463 if not found then
464 raise bad_end; -- Definitely no "end-of-central-directory" in this stream
465 end if;
466 end;
467 --
468 -- Zip64
469 --
470 if Is_64 then
471 Set_Index (stream, Index (stream) - 42);
472 Read_and_Check (stream, end_64_loc);
473 -- We zero the offset shifting. This assumes that the offsets are as
474 -- written, i.e. the Zip file is not appended to another file.
475 -- The reason is that the "Zip64 end of central directory" has
476 -- an 64-bit unknown size and thus can only reached by the stored offset,
477 -- not via a calculation using the stream index, or via heurisitcs as above
478 -- for the "Zip32".
479 the_end.offset_shifting := 0;
480 Set_Index (stream,
481 ZS_Index_Type
482 (end_64_loc.relative_offset_of_the_zip64_end_of_central_dir_record) +
483 the_end.offset_shifting + 1);
484 Read_and_Check (stream, end_64);
485 the_end.disknum := end_64.number_of_this_disk;
486 the_end.disknum_with_start := end_64.number_of_the_disk_with_the_start_of_the_central_directory;
487 the_end.disk_total_entries := end_64.total_number_of_entries_in_the_central_directory_on_this_disk;
488 the_end.total_entries := end_64.total_number_of_entries_in_the_central_directory;
489 the_end.central_dir_size := end_64.size_of_the_central_directory;
490 the_end.central_dir_offset := end_64.offset_of_start_of_central_directory;
491 end if;
492 end Load;
493
494 procedure Write
495 (stream : in out Root_Zipstream_Type'Class;
496 the_end : in End_of_Central_Dir)
497 is
498 eb : Byte_Buffer (1 .. 22);
499 begin
500 PK_signature (eb, 5, 6);
501
502 eb (5 .. 6) := Intel_bf (Unsigned_16 (the_end.disknum));
503 eb (7 .. 8) := Intel_bf (Unsigned_16 (the_end.disknum_with_start));
504 eb (9 .. 10) := Intel_bf (Unsigned_16 (the_end.disk_total_entries));
505 eb (11 .. 12) := Intel_bf (Unsigned_16 (the_end.total_entries));
506 eb (13 .. 16) := Intel_bf (Unsigned_32 (the_end.central_dir_size));
507 eb (17 .. 20) := Intel_bf (Unsigned_32 (the_end.central_dir_offset));
508 eb (21 .. 22) := Intel_bf (the_end.main_comment_length);
509
510 Block_Write (stream, eb);
511 end Write;
512
513 procedure Read_and_Check
514 (stream : in out Root_Zipstream_Type'Class;
515 the_end_64 : out Zip64_End_of_Central_Dir)
516 is
517 eb : Byte_Buffer (1 .. zip_64_end_of_central_dir_length);
518 begin
519 Block_Read (stream, eb);
520 if not PK_signature (eb, 6, 6) then
521 raise bad_end with "Zip64_End_of_Central_Dir";
522 end if;
523 the_end_64.size := Intel_nb (eb (5 .. 12));
524 the_end_64.version_made_by := Intel_nb (eb (13 .. 14));
525 the_end_64.version_needed_to_extract := Intel_nb (eb (15 .. 16));
526 the_end_64.number_of_this_disk := Intel_nb (eb (17 .. 20));
527 the_end_64.number_of_the_disk_with_the_start_of_the_central_directory := Intel_nb (eb (21 .. 24));
528 the_end_64.total_number_of_entries_in_the_central_directory_on_this_disk := Intel_nb (eb (25 .. 32));
529 the_end_64.total_number_of_entries_in_the_central_directory := Intel_nb (eb (33 .. 40));
530 the_end_64.size_of_the_central_directory := Intel_nb (eb (41 .. 48));
531 the_end_64.offset_of_start_of_central_directory := Intel_nb (eb (49 .. 56));
532 end Read_and_Check;
533
534 procedure Write
535 (stream : in out Root_Zipstream_Type'Class;
536 the_end_64 : in Zip64_End_of_Central_Dir)
537 is
538 eb : Byte_Buffer (1 .. zip_64_end_of_central_dir_length);
539 begin
540 PK_signature (eb, 6, 6);
541 eb (5 .. 12) := Intel_bf (the_end_64.size);
542 eb (13 .. 14) := Intel_bf (the_end_64.version_made_by);
543 eb (15 .. 16) := Intel_bf (the_end_64.version_needed_to_extract);
544 eb (17 .. 20) := Intel_bf (the_end_64.number_of_this_disk);
545 eb (21 .. 24) := Intel_bf (the_end_64.number_of_the_disk_with_the_start_of_the_central_directory);
546 eb (25 .. 32) := Intel_bf (the_end_64.total_number_of_entries_in_the_central_directory_on_this_disk);
547 eb (33 .. 40) := Intel_bf (the_end_64.total_number_of_entries_in_the_central_directory);
548 eb (41 .. 48) := Intel_bf (the_end_64.size_of_the_central_directory);
549 eb (49 .. 56) := Intel_bf (the_end_64.offset_of_start_of_central_directory);
550 Block_Write (stream, eb);
551 end Write;
552
553 procedure Read_and_Check
554 (stream : in out Root_Zipstream_Type'Class;
555 the_end_64_loc : out Zip64_End_of_Central_Dir_Locator)
556 is
557 eb : Byte_Buffer (1 .. zip_64_end_of_central_dir_locator_length);
558 begin
559 Block_Read (stream, eb);
560 if not PK_signature (eb, 6, 7) then
561 raise bad_end with "Zip64_End_of_Central_Dir_Locator";
562 end if;
563 the_end_64_loc.number_of_the_disk_with_the_start_of_the_zip64_end_of_central_dir := Intel_nb (eb (5 .. 8));
564 the_end_64_loc.relative_offset_of_the_zip64_end_of_central_dir_record := Intel_nb (eb (9 .. 16));
565 the_end_64_loc.total_number_of_disks := Intel_nb (eb (17 .. 20));
566 end Read_and_Check;
567
568 procedure Write
569 (stream : in out Root_Zipstream_Type'Class;
570 the_end_64_loc : in Zip64_End_of_Central_Dir_Locator)
571 is
572 eb : Byte_Buffer (1 .. zip_64_end_of_central_dir_locator_length);
573 begin
574 PK_signature (eb, 6, 7);
575 eb (5 .. 8) := Intel_bf (the_end_64_loc.number_of_the_disk_with_the_start_of_the_zip64_end_of_central_dir);
576 eb (9 .. 16) := Intel_bf (the_end_64_loc.relative_offset_of_the_zip64_end_of_central_dir_record);
577 eb (17 .. 20) := Intel_bf (the_end_64_loc.total_number_of_disks);
578 Block_Write (stream, eb);
579 end Write;
580
581 end Zip.Headers;
Web view of Ada source code generated by GNATHTML, project: ALI_Parse version 1.0.
Zip-Ada: Ada library for zip archive files (.zip).
Ada programming.
Some news about Zip-Ada and other Ada projects
on Gautier's blog.