Class: Cabriolet::SZDD::Decompressor
- Inherits:
-
Object
- Object
- Cabriolet::SZDD::Decompressor
- Defined in:
- lib/cabriolet/szdd/decompressor.rb
Overview
Decompressor is the main interface for SZDD file operations
SZDD files use LZSS compression and are decompressed using the Decompressors::LZSS class with appropriate mode settings.
Constant Summary collapse
- DEFAULT_BUFFER_SIZE =
Input buffer size for decompression
2048
Instance Attribute Summary collapse
-
#buffer_size ⇒ Object
Returns the value of attribute buffer_size.
-
#io_system ⇒ Object
readonly
Returns the value of attribute io_system.
-
#parser ⇒ Object
readonly
Returns the value of attribute parser.
Instance Method Summary collapse
-
#auto_output_filename(input_path, header) ⇒ String
Generate output filename from input filename and header.
-
#close(_header) ⇒ void
Close an SZDD file (no-op for compatibility).
-
#decompress(input_path, output_path = nil) ⇒ Integer
One-shot decompression from input file to output file.
-
#extract(header, output_path) ⇒ Integer
Extract an SZDD file to output.
-
#extract_to_memory(header) ⇒ String
Extract SZDD file to memory.
-
#initialize(io_system = nil, algorithm_factory = nil) ⇒ Decompressor
constructor
Initialize a new SZDD decompressor.
-
#open(filename) ⇒ Models::SZDDHeader
Open and parse an SZDD file.
Constructor Details
#initialize(io_system = nil, algorithm_factory = nil) ⇒ Decompressor
Initialize a new SZDD decompressor
21 22 23 24 25 26 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 21 def initialize(io_system = nil, algorithm_factory = nil) @io_system = io_system || System::IOSystem.new @algorithm_factory = algorithm_factory || Cabriolet.algorithm_factory @parser = Parser.new(@io_system) @buffer_size = DEFAULT_BUFFER_SIZE end |
Instance Attribute Details
#buffer_size ⇒ Object
Returns the value of attribute buffer_size.
11 12 13 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 11 def buffer_size @buffer_size end |
#io_system ⇒ Object (readonly)
Returns the value of attribute io_system.
10 11 12 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 10 def io_system @io_system end |
#parser ⇒ Object (readonly)
Returns the value of attribute parser.
10 11 12 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 10 def parser @parser end |
Instance Method Details
#auto_output_filename(input_path, header) ⇒ String
Generate output filename from input filename and header
177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 177 def auto_output_filename(input_path, header) # Get base filename without directory base = ::File.basename(input_path) # Use header's suggested filename method suggested = header.suggested_filename(base) # Strip null bytes which can occur in malformed SZDD files suggested = suggested.delete("\0") # Combine with original directory dir = ::File.dirname(input_path) ::File.join(dir, suggested) end |
#close(_header) ⇒ void
This method returns an undefined value.
Close an SZDD file (no-op for compatibility)
43 44 45 46 47 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 43 def close(_header) # No resources to free in the header itself # File handles are managed separately during extraction nil end |
#decompress(input_path, output_path = nil) ⇒ Integer
One-shot decompression from input file to output file
This method combines open(), extract(), and close() for convenience. Similar to MS-DOS EXPAND.EXE behavior.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 156 def decompress(input_path, output_path = nil) # Parse header header = self.open(input_path) # Auto-detect output filename if not provided output_path ||= auto_output_filename(input_path, header) # Extract bytes_written = extract(header, output_path) # Close (no-op but kept for API consistency) close(header) bytes_written end |
#extract(header, output_path) ⇒ Integer
Extract an SZDD file to output
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 96 97 98 99 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 55 def extract(header, output_path) raise ArgumentError, "Header must not be nil" unless header raise ArgumentError, "Output path must not be nil" unless output_path input_handle = @io_system.open(header.filename, Constants::MODE_READ) output_handle = @io_system.open(output_path, Constants::MODE_WRITE) begin # Seek to compressed data start data_offset = @parser.data_offset(header.format) @io_system.seek(input_handle, data_offset, Constants::SEEK_START) # Determine LZSS mode based on format lzss_mode = if header.normal_format? Decompressors::LZSS::MODE_EXPAND else Decompressors::LZSS::MODE_QBASIC end # Create LZSS decompressor decompressor = @algorithm_factory.create( :lzss, :decompressor, @io_system, input_handle, output_handle, @buffer_size, mode: lzss_mode, ) # Decompress (SZDD reads until EOF, no compressed size stored) bytes_written = decompressor.decompress(nil) # Verify decompressed size matches expected if bytes_written != header.length && Cabriolet.verbose && Cabriolet.verbose warn "[Cabriolet] WARNING; decompressed #{bytes_written} bytes, " \ "expected #{header.length} bytes" end bytes_written ensure @io_system.close(input_handle) if input_handle @io_system.close(output_handle) if output_handle end end |
#extract_to_memory(header) ⇒ String
Extract SZDD file to memory
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 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 106 def extract_to_memory(header) raise ArgumentError, "Header must not be nil" unless header input_handle = @io_system.open(header.filename, Constants::MODE_READ) output_handle = System::MemoryHandle.new("", Constants::MODE_WRITE) begin # Seek to compressed data start data_offset = @parser.data_offset(header.format) @io_system.seek(input_handle, data_offset, Constants::SEEK_START) # Determine LZSS mode based on format lzss_mode = if header.normal_format? Decompressors::LZSS::MODE_EXPAND else Decompressors::LZSS::MODE_QBASIC end # Create LZSS decompressor decompressor = @algorithm_factory.create( :lzss, :decompressor, @io_system, input_handle, output_handle, @buffer_size, mode: lzss_mode, ) # Decompress (SZDD reads until EOF, no compressed size stored) decompressor.decompress(nil) # Return the decompressed data output_handle.data ensure @io_system.close(input_handle) if input_handle end end |
#open(filename) ⇒ Models::SZDDHeader
Open and parse an SZDD file
33 34 35 36 37 |
# File 'lib/cabriolet/szdd/decompressor.rb', line 33 def open(filename) header = @parser.parse(filename) header.filename = filename header end |