Class: Omnizip::Algorithms::Deflate64::Decoder

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/omnizip/algorithms/deflate64/decoder.rb

Overview

Deflate64 decoder

Constant Summary

Constants included from Constants

Constants::BLOCK_TYPE_DYNAMIC, Constants::BLOCK_TYPE_FIXED, Constants::BLOCK_TYPE_STORED, Constants::DICTIONARY_SIZE, Constants::DISTANCE_CODES, Constants::END_OF_BLOCK, Constants::GOOD_MATCH, Constants::HASH_SHIFT, Constants::HASH_SIZE, Constants::LENGTH_CODES, Constants::LITERAL_CODES, Constants::MAX_CHAIN_LENGTH, Constants::MAX_DISTANCE, Constants::MAX_DISTANCE_CODE_LENGTH, Constants::MAX_LAZY_MATCH, Constants::MAX_LITERAL_CODE_LENGTH, Constants::MAX_MATCH_LENGTH, Constants::MIN_MATCH_LENGTH, Constants::NICE_MATCH

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_stream) ⇒ Decoder

Returns a new instance of Decoder.



14
15
16
17
18
19
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 14

def initialize(input_stream)
  @input_stream = input_stream
  @window_size = DICTIONARY_SIZE
  @window = []
  @huffman = HuffmanCoder.new
end

Instance Attribute Details

#window_sizeObject (readonly)

Returns the value of attribute window_size.



12
13
14
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 12

def window_size
  @window_size
end

Instance Method Details

#decode_block(data) ⇒ String

Decode single block

Parameters:

  • data (String)

    Compressed block

Returns:

  • (String)

    Decompressed data



109
110
111
112
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 109

def decode_block(data)
  tokens = @huffman.decode(data, {}, {})
  reconstruct_from_tokens(tokens)
end

#decompress(output_stream) ⇒ Object

Decompress input stream to output stream

Parameters:

  • output_stream (IO)

    Output data stream



24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 24

def decompress(output_stream)
  compressed_data = @input_stream.read

  # Deserialize trees and compressed data
  literal_tree, distance_tree, data = deserialize_with_trees(compressed_data)

  # Decode Huffman-encoded data
  tokens = @huffman.decode(data, literal_tree, distance_tree)

  # Reconstruct data from LZ77 tokens
  decompressed = reconstruct_from_tokens(tokens)

  output_stream.write(decompressed)
end

#deserialize_with_trees(data) ⇒ Array

Deserialize compressed data with Huffman trees

Parameters:

  • data (String)

    Serialized compressed data

Returns:

  • (Array)

    Literal tree, distance tree, compressed data



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 43

def deserialize_with_trees(data)
  # Extract sizes (4 bytes each)
  literal_size, distance_size = data.unpack("NN")
  offset = 8

  # Extract literal tree JSON
  literal_json = data[offset, literal_size]
  offset += literal_size

  # Extract distance tree JSON
  distance_json = data[offset, distance_size]
  offset += distance_size

  # Extract compressed data
  compressed = data[offset..]

  # Parse trees from JSON with symbol keys as integers
  literal_tree = parse_tree_from_json(literal_json)
  distance_tree = parse_tree_from_json(distance_json)

  [literal_tree, distance_tree, compressed]
end

#parse_tree_from_json(json) ⇒ Hash

Parse Huffman tree from JSON with integer keys

Parameters:

  • json (String)

    JSON string

Returns:

  • (Hash)

    Huffman tree with integer keys



70
71
72
73
74
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 70

def parse_tree_from_json(json)
  parsed = JSON.parse(json)
  # Convert string keys back to integers
  parsed.transform_keys(&:to_i)
end

#reconstruct_from_tokens(tokens) ⇒ String

Reconstruct data from LZ77 tokens

Parameters:

  • tokens (Array<Hash>)

    LZ77 tokens

Returns:

  • (String)

    Decompressed data



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/omnizip/algorithms/deflate64/decoder.rb', line 80

def reconstruct_from_tokens(tokens)
  output = []

  tokens.each do |token|
    if token[:type] == :literal
      byte_char = token[:value].chr(Encoding::BINARY)
      output << byte_char
      @window << token[:value]
    elsif token[:type] == :match
      copy_from_window(
        output,
        token[:distance],
        token[:length],
      )
    end

    # Maintain 64KB window
    while @window.size > @window_size
      @window.shift
    end
  end

  output.join.force_encoding(Encoding::BINARY)
end