Method: ZipTricks::ZipWriter#write_local_file_header

Defined in:
lib/zip_tricks/zip_writer.rb

#write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:) ⇒ void

This method returns an undefined value.

Writes the local file header, that precedes the actual file data.

Parameters:

  • io (#<<)

    the buffer to write the local file header to

  • filename (String)

    the name of the file in the archive

  • compressed_size (Fixnum)

    The size of the compressed (or stored) data - how much space it uses in the ZIP

  • uncompressed_size (Fixnum)

    The size of the file once extracted

  • crc32 (Fixnum)

    The CRC32 checksum of the file

  • mtime (Time)

    the modification time to be recorded in the ZIP

  • gp_flags (Fixnum)

    bit-packed general purpose flags

  • storage_mode (Fixnum)

    8 for deflated, 0 for stored...



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/zip_tricks/zip_writer.rb', line 85

def write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:)
  requires_zip64 = (compressed_size > FOUR_BYTE_MAX_UINT || uncompressed_size > FOUR_BYTE_MAX_UINT)

  io << [0x04034b50].pack(C_UINT4)                        # local file header signature     4 bytes  (0x04034b50)
  io << if requires_zip64                                 # version needed to extract       2 bytes
    [VERSION_NEEDED_TO_EXTRACT_ZIP64].pack(C_UINT2)
  else
    [VERSION_NEEDED_TO_EXTRACT].pack(C_UINT2)
  end

  io << [gp_flags].pack(C_UINT2)                          # general purpose bit flag        2 bytes
  io << [storage_mode].pack(C_UINT2)                      # compression method              2 bytes
  io << [to_binary_dos_time(mtime)].pack(C_UINT2)         # last mod file time              2 bytes
  io << [to_binary_dos_date(mtime)].pack(C_UINT2)         # last mod file date              2 bytes
  io << [crc32].pack(C_UINT4)                             # crc-32                          4 bytes

  if requires_zip64
    io << [FOUR_BYTE_MAX_UINT].pack(C_UINT4)              # compressed size              4 bytes
    io << [FOUR_BYTE_MAX_UINT].pack(C_UINT4)              # uncompressed size            4 bytes
  else
    io << [compressed_size].pack(C_UINT4)                 # compressed size              4 bytes
    io << [uncompressed_size].pack(C_UINT4)               # uncompressed size            4 bytes
  end

  # Filename should not be longer than 0xFFFF otherwise this wont fit here
  io << [filename.bytesize].pack(C_UINT2)                 # file name length             2 bytes

  extra_fields = StringIO.new

  # Interesting tidbit:
  # https://social.technet.microsoft.com/Forums/windows/en-US/6a60399f-2879-4859-b7ab-6ddd08a70948
  # TL;DR of it is: Windows 7 Explorer _will_ open Zip64 entries. However, it desires to have the
  # Zip64 extra field as _the first_ extra field.
  if requires_zip64
    extra_fields << zip_64_extra_for_local_file_header(compressed_size: compressed_size, uncompressed_size: uncompressed_size)
  end
  extra_fields << timestamp_extra_for_local_file_header(mtime)

  io << [extra_fields.size].pack(C_UINT2)                # extra field length              2 bytes

  io << filename                                     # file name (variable size)
  io << extra_fields.string
end