Class: Omnizip::Formats::Rar::Rar5::Compression::Lzss::HuffmanTable

Inherits:
Object
  • Object
show all
Defined in:
lib/omnizip/formats/rar/rar5/compression/lzss.rb

Overview

Huffman decode table

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(size) ⇒ HuffmanTable

Returns a new instance of HuffmanTable.



207
208
209
210
211
212
213
214
215
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 207

def initialize(size)
  @size = size
  @decode_len = Array.new(16, 0)
  @decode_pos = Array.new(16, 0)
  @decode_num = Array.new(size, 0)
  @quick_bits = 0
  @quick_len = Array.new(65536, 0)
  @quick_num = Array.new(65536, 0)
end

Instance Attribute Details

#decode_lenObject (readonly)

Returns the value of attribute decode_len.



205
206
207
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 205

def decode_len
  @decode_len
end

#decode_numObject (readonly)

Returns the value of attribute decode_num.



205
206
207
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 205

def decode_num
  @decode_num
end

#decode_posObject (readonly)

Returns the value of attribute decode_pos.



205
206
207
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 205

def decode_pos
  @decode_pos
end

#sizeObject (readonly)

Returns the value of attribute size.



205
206
207
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 205

def size
  @size
end

Instance Method Details

#build(bit_lengths) ⇒ Object

Build decode tables from bit lengths Based on libarchive's create_decode_tables()



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 219

def build(bit_lengths)
  # Count codes for each bit length
  len_count = Array.new(16, 0)
  bit_lengths.each do |len|
    len_count[len] += 1 if len.positive? && len < 16
  end

  # Calculate decode_len and decode_pos
  @decode_pos[0] = 0
  @decode_len[0] = 0

  upper_limit = 0
  (1..15).each do |i|
    upper_limit = (upper_limit + len_count[i]) << 1
    @decode_len[i] = upper_limit << (16 - i)
    @decode_pos[i] = @decode_pos[i - 1] + len_count[i - 1]
  end

  # Fill decode_num
  decode_pos_copy = @decode_pos.dup
  bit_lengths.each_with_index do |len, symbol|
    next unless len.positive? && len < 16

    pos = decode_pos_copy[len]
    @decode_num[pos] = symbol if pos < @size
    decode_pos_copy[len] += 1
  end

  # Build quick lookup table
  @quick_bits = 10 # Use 10 bits for quick lookup
  build_quick_table(bit_lengths)

  true
end

#decode(bit_reader) ⇒ Object

Decode a symbol from bit reader



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 255

def decode(bit_reader)
  # Read 16 bits for lookup
  bit_field = bit_reader.read_bits(16)
  return nil if bit_field.nil?

  # Quick lookup
  if @quick_len[bit_field].positive?
    bit_reader.skip_bits(@quick_len[bit_field])
    return @quick_num[bit_field]
  end

  # Full decode
  bits = 15
  (1..14).each do |i|
    if bit_field < @decode_len[i]
      bits = i
      break
    end
  end

  bit_reader.skip_bits(bits)

  dist = bit_field - @decode_len[bits - 1]
  dist >>= (16 - bits)
  pos = @decode_pos[bits] + dist

  pos < @size ? @decode_num[pos] : 0
end