Class: Omnizip::Implementations::SevenZip::LZMA::RangeDecoder

Inherits:
Object
  • Object
show all
Includes:
Algorithms::LZMA::Constants
Defined in:
lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb

Overview

Range decoder for 7-Zip SDK LZMA decompression

This is a direct port of 7-Zip SDK's range decoder implementation from LzmaDec.c for guaranteed compatibility with 7-Zip archives.

Reference: /Users/mulgogi/src/external/7-Zip/C/LzmaDec.c

Constant Summary

Constants included from Algorithms::LZMA::Constants

Algorithms::LZMA::Constants::BIT_MODEL_TOTAL, Algorithms::LZMA::Constants::COMPRESSION_LEVEL_DEFAULT, Algorithms::LZMA::Constants::COMPRESSION_LEVEL_MAX, Algorithms::LZMA::Constants::COMPRESSION_LEVEL_MIN, Algorithms::LZMA::Constants::DICT_SIZE_MAX, Algorithms::LZMA::Constants::DICT_SIZE_MIN, Algorithms::LZMA::Constants::DIST_ALIGN_BITS, Algorithms::LZMA::Constants::DIST_ALIGN_SIZE, Algorithms::LZMA::Constants::DIST_SLOT_FAST_LIMIT, Algorithms::LZMA::Constants::END_POS_MODEL_INDEX, Algorithms::LZMA::Constants::EOS_MARKER, Algorithms::LZMA::Constants::INIT_PROBS, Algorithms::LZMA::Constants::LEN_HIGH_SYMBOLS, Algorithms::LZMA::Constants::LEN_LOW_SYMBOLS, Algorithms::LZMA::Constants::LEN_MID_SYMBOLS, Algorithms::LZMA::Constants::LIT_SIZE_MAX, Algorithms::LZMA::Constants::MATCH_LEN_MAX, Algorithms::LZMA::Constants::MATCH_LEN_MIN, Algorithms::LZMA::Constants::MOVE_BITS, Algorithms::LZMA::Constants::NUM_DIRECT_BITS, Algorithms::LZMA::Constants::NUM_DIST_SLOTS, Algorithms::LZMA::Constants::NUM_DIST_SLOT_BITS, Algorithms::LZMA::Constants::NUM_FULL_DISTANCES, Algorithms::LZMA::Constants::NUM_LEN_HIGH_BITS, Algorithms::LZMA::Constants::NUM_LEN_LOW_BITS, Algorithms::LZMA::Constants::NUM_LEN_MID_BITS, Algorithms::LZMA::Constants::NUM_LEN_TO_POS_STATES, Algorithms::LZMA::Constants::NUM_LIT_CONTEXT_BITS_MAX, Algorithms::LZMA::Constants::NUM_LIT_POS_BITS_MAX, Algorithms::LZMA::Constants::NUM_POS_BITS_MAX, Algorithms::LZMA::Constants::NUM_STATES, Algorithms::LZMA::Constants::POS_STATES_MAX, Algorithms::LZMA::Constants::START_POS_MODEL_INDEX, Algorithms::LZMA::Constants::TOP

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_stream) ⇒ RangeDecoder

Initialize the range decoder

Parameters:

  • input_stream (IO)

    The input stream of encoded bytes



45
46
47
48
49
50
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 45

def initialize(input_stream)
  @stream = input_stream
  @range = 0xFFFFFFFF
  @code = 0
  init_decoder
end

Instance Attribute Details

#codeObject (readonly)

Returns the value of attribute code.



40
41
42
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 40

def code
  @code
end

Instance Method Details

#decode_bit(model) ⇒ Integer

Decode a single bit using a probability model

Ported from 7-Zip SDK IF_BIT_0/UPDATE_0/UPDATE_1 macros (LzmaDec.c lines 22-26)

SDK pattern:

#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));

Parameters:

  • model (BitModel)

    The probability model for this bit

Returns:

  • (Integer)

    The decoded bit value (0 or 1)



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 64

def decode_bit(model)
  prob = model.probability

  # NORMALIZE (SDK pattern: normalize BEFORE decoding)
  normalize

  # Calculate bound
  bound = (@range >> 11) * prob

  if @code < bound
    # UPDATE_0: bit is 0
    @range = bound & 0xFFFFFFFF
    new_prob = prob + ((BIT_MODEL_TOTAL - prob) >> MOVE_BITS)
    model.probability = new_prob
    0
  else
    # UPDATE_1: bit is 1
    @range = (@range - bound) & 0xFFFFFFFF
    @code = (@code - bound) & 0xFFFFFFFF
    new_prob = prob - (prob >> MOVE_BITS)
    model.probability = new_prob
    1
  end
end

#decode_direct_bits(num_bits) ⇒ Integer

Decode bits directly without using probability model

Parameters:

  • num_bits (Integer)

    Number of bits to decode

Returns:

  • (Integer)

    The decoded value



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 93

def decode_direct_bits(num_bits)
  result = 0
  num_bits.times do
    normalize
    @range >>= 1
    @range &= 0xFFFFFFFF
    @code = (@code - @range) & 0xFFFFFFFF
    bit = (@code >> 31) & 1
    @code = (@code + (@range & (0 - bit))) & 0xFFFFFFFF
    result = (result << 1) | bit
  end
  result
end

#decode_direct_bits_with_base(num_bits, base) ⇒ Integer

Decode bits directly with a base value

Used by distance decoder for slots 14+ where we need to build on a base value (2 or 3) iteratively.

Parameters:

  • num_bits (Integer)

    Number of bits to decode

  • base (Integer)

    Base value to start from

Returns:

  • (Integer)

    The decoded value



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 115

def decode_direct_bits_with_base(num_bits, base)
  result = base
  num_bits.times do
    result = (result << 1) + 1
    normalize
    @range >>= 1
    @range &= 0xFFFFFFFF

    # Check if bit is 1
    bit = @code >= @range ? 1 : 0

    if bit == 1
      @code = (@code - @range) & 0xFFFFFFFF
    else
      result -= 1
    end
  end
  result
end

#resetvoid

This method returns an undefined value.

Reset the decoder state (for LZMA2 chunks)



146
147
148
149
150
151
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 146

def reset
  @range = 0xFFFFFFFF
  @code = 0
  # Read initial 5 bytes for code
  5.times { @code = ((@code << 8) | read_byte) & 0xFFFFFFFF }
end

#update_stream(new_stream) ⇒ void

This method returns an undefined value.

Update the input stream (for LZMA2 multi-chunk streams)

Parameters:

  • new_stream (IO)

    New input stream



139
140
141
# File 'lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb', line 139

def update_stream(new_stream)
  @stream = new_stream
end