Class: Omnizip::Formats::SevenZip::StreamDecompressor
- Inherits:
-
Object
- Object
- Omnizip::Formats::SevenZip::StreamDecompressor
- Defined in:
- lib/omnizip/formats/seven_zip/stream_decompressor.rb
Overview
Decompresses .7z streams using coder chains Handles packed stream extraction and CRC validation
Instance Attribute Summary collapse
-
#archive_io ⇒ Object
readonly
Returns the value of attribute archive_io.
-
#chain_config ⇒ Object
readonly
Returns the value of attribute chain_config.
-
#folder ⇒ Object
readonly
Returns the value of attribute folder.
Instance Method Summary collapse
-
#decompress(size) ⇒ String
Decompress stream to output.
-
#decompress_and_verify(size, expected_crc = nil) ⇒ String
Decompress and verify CRC.
-
#initialize(archive_io, folder, pack_pos, pack_size, header = nil) ⇒ StreamDecompressor
constructor
Initialize decompressor.
Constructor Details
#initialize(archive_io, folder, pack_pos, pack_size, header = nil) ⇒ StreamDecompressor
Initialize decompressor
20 21 22 23 24 25 26 27 |
# File 'lib/omnizip/formats/seven_zip/stream_decompressor.rb', line 20 def initialize(archive_io, folder, pack_pos, pack_size, header = nil) @archive_io = archive_io @folder = folder @pack_pos = pack_pos @pack_size = pack_size @header = header @chain_config = CoderChain.build_from_folder(folder) end |
Instance Attribute Details
#archive_io ⇒ Object (readonly)
Returns the value of attribute archive_io.
11 12 13 |
# File 'lib/omnizip/formats/seven_zip/stream_decompressor.rb', line 11 def archive_io @archive_io end |
#chain_config ⇒ Object (readonly)
Returns the value of attribute chain_config.
11 12 13 |
# File 'lib/omnizip/formats/seven_zip/stream_decompressor.rb', line 11 def chain_config @chain_config end |
#folder ⇒ Object (readonly)
Returns the value of attribute folder.
11 12 13 |
# File 'lib/omnizip/formats/seven_zip/stream_decompressor.rb', line 11 def folder @folder end |
Instance Method Details
#decompress(size) ⇒ String
Decompress stream to output
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/omnizip/formats/seven_zip/stream_decompressor.rb', line 34 def decompress(size) # Seek to packed data @archive_io.seek(@pack_pos) # For multi-volume archives, pack_size from stream_info may be incomplete. # For solid archives spanning volumes, the actual compressed data extends # from pack_pos to where the next header starts. if @archive_io.is_a?(SplitArchiveReader::MultiVolumeIO) && @header # next_header_offset is relative to start_pos_after_header # Actual packed data size is from pack_pos to next header position next_header_position = @header.start_pos_after_header + @header.next_header_offset actual_pack_size = next_header_position - @pack_pos packed_data = @archive_io.read(actual_pack_size) else # Regular single-file archive: use pack_size from stream info packed_data = @archive_io.read(@pack_size) end return packed_data if @chain_config.nil? # No compression # Get algorithm algo_sym = @chain_config[:algorithm] return packed_data unless algo_sym # Copy method # Get algorithm class algo_class = Omnizip::AlgorithmRegistry.get(algo_sym) raise "Algorithm not found: #{algo_sym}" unless algo_class # Decompress input_io = StringIO.new(packed_data) output_io = StringIO.new output_io.set_encoding("BINARY") # Build options from coder properties for 7-Zip format = decoder = algo_class.new() decoder.decompress(input_io, output_io, size: size) result = output_io.string # Apply filters if present if @chain_config[:filters] && !@chain_config[:filters].empty? @chain_config[:filters].reverse_each do |filter_sym| filter_class = Omnizip::FilterRegistry.get(filter_sym) next unless filter_class # BCJ2 requires special handling with multiple streams if filter_sym == :bcj2 raise "BCJ2 archives require multi-stream decompression which is not yet implemented. " \ "Please use the 7z command-line tool for this archive." end filter = filter_class.new filtered = StringIO.new filter.reverse(StringIO.new(result), filtered) result = filtered.string end end result end |
#decompress_and_verify(size, expected_crc = nil) ⇒ String
Decompress and verify CRC
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/omnizip/formats/seven_zip/stream_decompressor.rb', line 103 def decompress_and_verify(size, expected_crc = nil) data = decompress(size) if expected_crc crc = Omnizip::Checksums::Crc32.new crc.update(data) actual_crc = crc.value unless actual_crc == expected_crc raise "CRC mismatch: expected 0x#{expected_crc.to_s(16)}, " \ "got 0x#{actual_crc.to_s(16)}" end end data end |