Class: OPA::ZipIO::Reader
- Inherits:
-
Object
- Object
- OPA::ZipIO::Reader
- Defined in:
- lib/opa/zip_io.rb
Overview
Reads entries from a ZIP archive.
Defined Under Namespace
Classes: ParsedEntry
Class Method Summary collapse
Class Method Details
.read(data) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/opa/zip_io.rb', line 104 def self.read(data) data = data.b entries = {} # Find end of central directory record eocd_pos = data.rindex([0x06054b50].pack("V")) raise "Invalid ZIP: no EOCD record" unless eocd_pos cd_size = data[eocd_pos + 12, 4].unpack1("V") cd_offset = data[eocd_pos + 16, 4].unpack1("V") entry_count = data[eocd_pos + 10, 2].unpack1("v") # Parse central directory to get entry metadata pos = cd_offset entry_count.times do sig = data[pos, 4].unpack1("V") raise "Invalid CD entry signature" unless sig == 0x02014b50 compression = data[pos + 10, 2].unpack1("v") crc32 = data[pos + 16, 4].unpack1("V") comp_size = data[pos + 20, 4].unpack1("V") uncomp_size = data[pos + 24, 4].unpack1("V") name_len = data[pos + 28, 2].unpack1("v") extra_len = data[pos + 30, 2].unpack1("v") comment_len = data[pos + 32, 2].unpack1("v") local_offset = data[pos + 42, 4].unpack1("V") name = data[pos + 46, name_len].force_encoding("UTF-8") # Read from local file header to get actual data local_name_len = data[local_offset + 26, 2].unpack1("v") local_extra_len = data[local_offset + 28, 2].unpack1("v") data_start = local_offset + 30 + local_name_len + local_extra_len raw = data[data_start, comp_size] content = case compression when 0 then raw when 8 then Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(raw) else raise "Unsupported compression method: #{compression}" end entries[name] = content.force_encoding("UTF-8") pos += 46 + name_len + extra_len + comment_len end entries end |