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.



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

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.



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

def decode_len
  @decode_len
end

#decode_numObject (readonly)

Returns the value of attribute decode_num.



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

def decode_num
  @decode_num
end

#decode_posObject (readonly)

Returns the value of attribute decode_pos.



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

def decode_pos
  @decode_pos
end

#sizeObject (readonly)

Returns the value of attribute size.



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

def size
  @size
end

Instance Method Details

#build(bit_lengths) ⇒ Object

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



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
253
254
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 221

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



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
283
284
# File 'lib/omnizip/formats/rar/rar5/compression/lzss.rb', line 257

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