Class: Omnizip::Algorithms::LZMA2::Properties

Inherits:
Object
  • Object
show all
Includes:
Omnizip::Algorithms::LZMA2Const
Defined in:
lib/omnizip/algorithms/lzma2/properties.rb

Overview

LZMA2 Properties - handles dictionary size encoding/decoding

The LZMA2 format uses a single property byte that encodes the dictionary size. This is more compact than LZMA's multiple property bytes.

Dictionary size encoding formula:

dictSize = (2 | (props & 1)) << (props / 2 + 11)

This gives sizes from 4KB (props=0) to 4GB (props=40)

Note: In XZ format, the LZMA2 filter properties byte contains ONLY the dictionary size encoding. The lc/lp/pb parameters are encoded in the LZMA chunk properties (inside the compressed data).

Constant Summary

Constants included from Omnizip::Algorithms::LZMA2Const

Omnizip::Algorithms::LZMA2Const::CHUNK_MAX, Omnizip::Algorithms::LZMA2Const::CONTROL_END, Omnizip::Algorithms::LZMA2Const::CONTROL_LZMA_MIN, Omnizip::Algorithms::LZMA2Const::CONTROL_UNCOMPRESSED, Omnizip::Algorithms::LZMA2Const::CONTROL_UNCOMPRESSED_RESET, Omnizip::Algorithms::LZMA2Const::DICT_SIZE_MAX, Omnizip::Algorithms::LZMA2Const::DICT_SIZE_MIN, Omnizip::Algorithms::LZMA2Const::FLAG_RESET_DICT, Omnizip::Algorithms::LZMA2Const::FLAG_RESET_PROPERTIES, Omnizip::Algorithms::LZMA2Const::FLAG_RESET_STATE, Omnizip::Algorithms::LZMA2Const::FLAG_UNCOMPRESSED_SIZE, Omnizip::Algorithms::LZMA2Const::HEADER_MAX, Omnizip::Algorithms::LZMA2Const::HEADER_UNCOMPRESSED, Omnizip::Algorithms::LZMA2Const::UNCOMPRESSED_MAX

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dict_size) ⇒ Properties

Initialize properties from dictionary size

Parameters:

  • dict_size (Integer)

    Dictionary size in bytes



48
49
50
51
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 48

def initialize(dict_size)
  @dict_size = validate_dict_size(dict_size)
  @prop_byte = encode_dict_size(@dict_size)
end

Instance Attribute Details

#dict_sizeObject (readonly)

Returns the value of attribute dict_size.



43
44
45
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 43

def dict_size
  @dict_size
end

#prop_byteObject (readonly)

Returns the value of attribute prop_byte.



43
44
45
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 43

def prop_byte
  @prop_byte
end

Class Method Details

.decode_dict_size(prop) ⇒ Integer

Decode property byte to dictionary size

XZ Utils formula from lzma_lzma2_props_decode (lzma2_decoder.c:290-302):

dict_size = (2 | (props & 1)) << (props / 2 + 11)

For even props: dict_size = 2 * 2^((props/2) + 11) = 2^((props/2) + 12) For odd props: dict_size = 3 * 2^((props-1)/2 + 11)

Parameters:

  • prop (Integer)

    Property byte

Returns:

  • (Integer)

    Dictionary size in bytes



89
90
91
92
93
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 89

def self.decode_dict_size(prop)
  # XZ Utils formula: dict_size = (2 | (prop & 1)) << (prop / 2 + 11)
  base = 2 | (prop & 1)
  base << ((prop / 2) + 11)
end

.encode(dict_size, _lc = 3, _lp = 0, _pb = 2) ⇒ Integer

Encode properties to property byte This is for standalone LZMA2 files where the property byte encodes both dictionary size and lc/lp/pb parameters

Parameters:

  • dict_size (Integer)

    Dictionary size

  • lc (Integer)

    Literal context bits

  • lp (Integer)

    Literal position bits

  • pb (Integer)

    Position bits

Returns:

  • (Integer)

    Property byte value



104
105
106
107
108
109
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 104

def self.encode(dict_size, _lc = 3, _lp = 0, _pb = 2)
  # For standalone LZMA2 files, we only encode the dictionary size
  # The lc/lp/pb parameters are encoded in the LZMA chunk properties instead
  validate_prop_byte_range(dict_size)
  encode_dict_size_to_byte(dict_size)
end

.encode_dict_size_to_byte(dict_size) ⇒ Integer

Encode dictionary size to property byte

Parameters:

  • dict_size (Integer)

    Dictionary size

Returns:

  • (Integer)

    Property byte value



115
116
117
118
119
120
121
122
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 115

def self.encode_dict_size_to_byte(dict_size)
  # Find the smallest prop value that gives >= dict_size
  (0..40).each do |prop|
    size = decode_dict_size(prop)
    return prop if size >= dict_size
  end
  40
end

.from_byte(prop_byte) ⇒ Properties

Create properties from property byte

Parameters:

  • prop_byte (Integer)

    Encoded property byte

Returns:



57
58
59
60
61
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 57

def self.from_byte(prop_byte)
  validate_prop_byte(prop_byte)
  dict_size = decode_dict_size(prop_byte)
  new(dict_size)
end

.validate_prop_byte(prop) ⇒ void

This method returns an undefined value.

Validate property byte

Parameters:

  • prop (Integer)

    Property byte to validate

Raises:

  • (ArgumentError)

    If property byte is invalid



170
171
172
173
174
175
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 170

def self.validate_prop_byte(prop)
  return if prop.between?(0, 40)

  raise ArgumentError,
        "Property byte must be between 0 and 40"
end

.validate_prop_byte_range(size) ⇒ Object

Validate dictionary size for property byte encoding

Parameters:

  • size (Integer)

    Dictionary size to validate

Raises:

  • (ArgumentError)

    If size is invalid



128
129
130
131
132
133
134
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 128

def self.validate_prop_byte_range(size)
  unless size.between?(DICT_SIZE_MIN, DICT_SIZE_MAX)
    raise ArgumentError,
          "Dictionary size must be between #{DICT_SIZE_MIN} " \
          "and #{DICT_SIZE_MAX}"
  end
end

Instance Method Details

#actual_dict_sizeInteger

Get the actual dictionary size (may differ from requested)

Returns:

  • (Integer)

    Actual dictionary size (capped at 64MB to prevent memory exhaustion)



139
140
141
142
143
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 139

def actual_dict_size
  # Cap at 64MB to prevent memory exhaustion from malformed files
  max_dict = 64 * 1024 * 1024
  [self.class.decode_dict_size(@prop_byte), max_dict].min
end

#encode_dict_size(dict_size) ⇒ Integer

Encode dictionary size to property byte

Parameters:

  • dict_size (Integer)

    Dictionary size

Returns:

  • (Integer)

    Property byte value



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/omnizip/algorithms/lzma2/properties.rb', line 67

def encode_dict_size(dict_size)
  # Find the smallest prop value that gives >= dict_size
  # Valid range for property byte is 0-40 (per XZ spec)
  (0..40).each do |prop|
    size = self.class.decode_dict_size(prop)
    return prop if size >= dict_size
  end

  # If we couldn't find a suitable prop, use maximum
  40
end