Class: Omnizip::Implementations::SevenZip::LZMA::Decoder

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

Overview

7-Zip SDK compatible LZMA decoder.

This decoder is designed to decode data encoded by the 7-Zip SDK encoder. Uses the same shared infrastructure (RangeDecoder, LengthCoder, DistanceCoder) to ensure model layout compatibility with the encoder.

Constant Summary collapse

MAX_DICT_SIZE =

Maximum dictionary size to prevent memory exhaustion 64MB is a reasonable practical limit

64 * 1024 * 1024

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, options = {}) ⇒ Decoder

Initialize 7-Zip LZMA decoder

Parameters:

  • input (IO)

    Input stream with LZMA compressed data

  • options (Hash) (defaults to: {})

    Decoding options

Options Hash (options):

  • :raw_mode (Boolean)

    Skip header parsing (for LZMA2)

  • :lc (Integer)

    Literal context bits

  • :lp (Integer)

    Literal position bits

  • :pb (Integer)

    Position bits

  • :dict_size (Integer)

    Dictionary size



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 50

def initialize(input, options = {})
  @input = input
  @raw_mode = options.fetch(:raw_mode, false)

  if @raw_mode
    @lc = options[:lc] || 3
    @lp = options[:lp] || 0
    @pb = options[:pb] || 2
    @dict_size = [[options[:dict_size] || (1 << 16), 1].max,
                  MAX_DICT_SIZE].min
    @uncompressed_size = options[:uncompressed_size]
  else
    parse_header
  end

  init_decoder
end

Instance Attribute Details

#dict_sizeObject (readonly)

Returns the value of attribute dict_size.



39
40
41
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 39

def dict_size
  @dict_size
end

#lcObject (readonly)

Returns the value of attribute lc.



39
40
41
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 39

def lc
  @lc
end

#lpObject (readonly)

Returns the value of attribute lp.



39
40
41
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 39

def lp
  @lp
end

#pbObject (readonly)

Returns the value of attribute pb.



39
40
41
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 39

def pb
  @pb
end

#uncompressed_sizeObject (readonly)

Returns the value of attribute uncompressed_size.



39
40
41
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 39

def uncompressed_size
  @uncompressed_size
end

Instance Method Details

#decode_stream(output = nil, preserve_dict: false) ⇒ String, Integer

Decode LZMA stream

Parameters:

  • output (IO, nil) (defaults to: nil)

    Output stream (if nil, returns String)

  • preserve_dict (Boolean) (defaults to: false)

    Preserve dictionary for chunked decoding

Returns:

  • (String, Integer)

    Decompressed data or bytes written



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
100
101
102
103
104
105
106
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 73

def decode_stream(output = nil, preserve_dict: false)
  @output_buffer = []
  unless preserve_dict && @dictionary
    @dictionary = Array.new(@dict_size,
                            0)
  end
  @dict_pos = 0
  @dict_full = false

  # Initialize range decoder (7-Zip SDK version)
  @range_decoder = RangeDecoder.new(@input)

  # Main decode loop
  loop do
    break if reached_end?

    # Track if we were using EOPM before decoding
    was_using_eopm = @allow_eopm

    decode_symbol

    # If we were using EOPM and now we're not, EOS was detected
    break if was_using_eopm && !@allow_eopm
  end

  result = @output_buffer.pack("C*").force_encoding(Encoding::BINARY)

  if output
    output.write(result)
    result.bytesize
  else
    result
  end
end

#reset(new_lc: nil, new_lp: nil, new_pb: nil, preserve_dict: false) ⇒ Object

Reset decoder state for new chunk (LZMA2)



109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 109

def reset(new_lc: nil, new_lp: nil, new_pb: nil, preserve_dict: false)
  @lc = new_lc if new_lc
  @lp = new_lp if new_lp
  @pb = new_pb if new_pb

  unless preserve_dict
    @dictionary = Array.new(@dict_size, 0)
    @dict_pos = 0
    @dict_full = false
  end

  init_decoder
end

#set_input(new_input) ⇒ Object

Set new input stream (LZMA2)



124
125
126
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 124

def set_input(new_input)
  @input = new_input
end

#set_uncompressed_size(size, allow_eopm: true) ⇒ Object

Set uncompressed size (LZMA2)



129
130
131
132
# File 'lib/omnizip/implementations/seven_zip/lzma/decoder.rb', line 129

def set_uncompressed_size(size, allow_eopm: true)
  @uncompressed_size = size
  @allow_eopm = allow_eopm
end