Skip to content

Commit

Permalink
Zip: explain the meaning of some numeric constants throught the code
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Jan 19, 2017
1 parent 4e7c5c7 commit 6952e76
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
19 changes: 18 additions & 1 deletion src/zip/file.cr
Expand Up @@ -81,6 +81,8 @@ class Zip::File
end
end

# Try to find the directory end offset (by searching its signature)
# in the last 64, 1024 and 65K bytes (in that order)
private def find_directory_end_offset
find_directory_end_offset(64) ||
find_directory_end_offset(1024) ||
Expand All @@ -100,6 +102,8 @@ class Zip::File

i = buf_size - 1 - 4
while i >= 0
# These are the bytes the make up the directory end signature,
# according to the spec
break if buf[i] == 0x50 && buf[i + 1] == 0x4b && buf[i + 2] == 0x05 && buf[i + 3] == 0x06
i -= 1
end
Expand Down Expand Up @@ -172,17 +176,30 @@ class Zip::File
# Apparently a zip entry might have different extra bytes
# in the local file header and central directory header,
# so to know the data offset we must read them again.
#
# The bytes inside a local file header, from the signature
# and up to the extra length field, sum up 30 bytes.
#
# This 30 and 22 constants are burned inside the zip spec and
# will never change.
@io.read_at(offset.to_i32, 30) do |io|
# at least check that the signature is OK
# at least check that the signature is OK (these are 4 bytes)
signature = read(io, UInt32)
if signature != FileInfo::SIGNATURE
raise Zip::Error.new("wrong local file header signature (expected 0x#{FileInfo::SIGNATURE.to_s(16)}, got 0x#{signature.to_s(16)})")
end

# Skip most of the headers except filename length and extra length
# (skip 22, so we already read 26 bytes)
io.skip(22)

# With these two we read 4 bytes more, so we are at 30 bytes
filename_length = read(io, UInt16)
extra_length = read(io, UInt16)

# The data of this entry comes at the local file header offset
# plus 30 bytes (the ones we just skipped) plus skipping the
# filename's bytes plus skipping the extra bytes.
@offset + 30 + filename_length + extra_length
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/zip/file_info.cr
Expand Up @@ -95,15 +95,15 @@ module Zip::FileInfo
write io, @uncompressed_size # 4
write io, @filename.bytesize.to_u16 # filename length (2)
write io, extra.size.to_u16 # extra field length (2)
24
24 # the 24 bytes we just wrote
end

protected def write_data_descriptor(io : IO)
io.write FileInfo::DEFLATE_END_SIGNATURE # 4
write io, @crc32 # 4
write io, @compressed_size # 4
write io, @uncompressed_size # 4
16
16 # the 16 bytes we just wrote
end

protected def decompressor_for(io, is_sized = false)
Expand Down
16 changes: 14 additions & 2 deletions src/zip/writer.cr
Expand Up @@ -34,9 +34,12 @@ class Zip::Writer
# Creates a new writer to the given *io*.
def initialize(@io : IO, @sync_close = false)
@entries = [] of Entry
@written = 0_u32
@compressed_size_counter = ChecksumWriter.new
@uncompressed_size_counter = ChecksumWriter.new(compute_crc32: true)

# Keep track of how many bytes we write, because we need
# that to write the offset of each local file header and some other info
@written = 0_u32
end

# Creates a new writer to the given *filename*.
Expand Down Expand Up @@ -188,16 +191,25 @@ class Zip::Writer
write Zip::CENTRAL_DIRECTORY_HEADER_SIGNATURE # 4
write Zip::VERSION # version made by (2)
write Zip::VERSION # version needed to extract (2)
@written += 8 # the 8 bytes we just wrote

@written += entry.meta_to_io(@io)

write entry.comment.bytesize.to_u16 # file comment length (2)
write 0_u16 # disk number start (2)
write 0_u16 # internal file attribute (2)
write 0_u32 # external file attribute (4)
write entry.offset # relative offset of local header (4)
@written += 14 # the 14 bytes we just wrote

@io << entry.filename
@written += entry.filename.bytesize

@io.write(entry.extra)
@written += entry.extra.size

@io << entry.comment
@written += 22 + entry.filename.bytesize + entry.extra.size + entry.comment.bytesize
@written += entry.comment.bytesize
end
end

Expand Down

0 comments on commit 6952e76

Please sign in to comment.