def self.parse(io)
cfr = parse_central_file_record(io)
next_record_position = io.pos
io.seek(cfr.local_header_position)
unless IOExtensions.read_exactly(io, 4) == LFH_SIGNATURE then
raise Zip::EntryError, 'bad local file header signature'
end
lfr = parse_local_file_record(io, cfr.compressed_size)
compare_file_records(lfr, cfr)
begin
compression_codec = Codec.create_compression_codec(
cfr.compression_method,
cfr.general_purpose_flags
)
rescue Zip::Error => e
raise Zip::EntryError, "`#{cfr.zip_path}': #{e.message}"
end
begin
encryption_codec = Codec.create_encryption_codec(
cfr.general_purpose_flags
)
rescue Zip::Error => e
raise Zip::EntryError, "`#{cfr.zip_path}': #{e.message}"
end
expected_data_descriptor = DataDescriptor.new(
cfr.crc32,
cfr.compressed_size,
cfr.uncompressed_size
)
expanded_path = expand_path(cfr.zip_path)
io_window = IOWindow.new(io, io.pos, cfr.compressed_size)
if cfr.zip_path[-1..-1] == '/' then
entry = Entry::Directory.new(expanded_path, io_window)
elsif (cfr.external_file_attributes >> 16) & 0770000 == 0120000 then
entry = Entry::Symlink.new(expanded_path, io_window)
else
entry = Entry::File.new(expanded_path, io_window)
end
entry.expected_data_descriptor = expected_data_descriptor
entry.compression_codec = compression_codec
entry.encryption_codec = encryption_codec
entry.mtime = cfr.mtime
if cfr.made_by_version & 0xFF00 == 0x0300 then
entry.mode = cfr.external_file_attributes >> 16
end
entry.comment = cfr.comment
cfr.extra_fields.each { |ef| entry.add_extra_field(ef) }
lfr.extra_fields.each { |ef| entry.add_extra_field(ef) }
io.seek(next_record_position)
entry
end