Back to... Zip-Ada

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.