Class: Omnizip::Algorithms::LZMA::XzEncoder

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/omnizip/algorithms/lzma/xz_encoder.rb

Overview

XZ Utils-compatible encoder main

Main encoding loop that coordinates all components:

  • Match finder for finding LZ77 matches
  • Fast encoder for greedy heuristics
  • Range encoder for arithmetic coding
  • State machine and probability models

Based on: xz/src/liblzma/lzma/lzma_encoder.c

Constant Summary

Constants included from Constants

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ XzEncoder

Initialize XZ encoder

Parameters:

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

    Encoding options

Options Hash (options):

  • :lc (Integer)

    Literal context bits (default 3)

  • :lp (Integer)

    Literal position bits (default 0)

  • :pb (Integer)

    Position bits (default 2)

  • :nice_len (Integer)

    Nice match length (default 32)

  • :dict_size (Integer)

    Dictionary size (default 8MB)



48
49
50
51
52
53
54
55
56
# File 'lib/omnizip/algorithms/lzma/xz_encoder.rb', line 48

def initialize(options = {})
  @lc = options[:lc] || 3
  @lp = options[:lp] || 0
  @pb = options[:pb] || 2
  @nice_len = options[:nice_len] || 32
  @dict_size = options[:dict_size] || (1 << 23) # 8MB default

  @output_total = 0
end

Instance Attribute Details

#output_totalObject (readonly)

Returns the value of attribute output_total.



38
39
40
# File 'lib/omnizip/algorithms/lzma/xz_encoder.rb', line 38

def output_total
  @output_total
end

Instance Method Details

#encode(input_data, output_stream) ⇒ Integer

Encode input data to output stream

Parameters:

  • input_data (String, Array<Integer>)

    Input data

  • output_stream (IO, StringIO)

    Output stream

Returns:

  • (Integer)

    Number of bytes decoder will consume (excludes flush padding)



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/omnizip/algorithms/lzma/xz_encoder.rb', line 63

def encode(input_data, output_stream)
  # Write LZMA header first (use unknown size to trigger EOS marker)
  write_header(output_stream)

  # Setup components
  setup_components(input_data, output_stream)

  # Main encoding loop
  encode_main_loop

  # Flush encoder
  flush_encoder(output_stream)

  # Return bytes decoder will consume (excludes flush padding for LZMA2 compatibility)
  @fast.bytes_for_decode
end

#write_header(output) ⇒ void

This method returns an undefined value.

Write LZMA header to output stream

Format (matching XZ Utils lzma_lzma_props_encode):

  • Property byte: (pb * 5 + lp) * 9 + lc
  • Dictionary size: 4 bytes little-endian
  • Uncompressed size: 8 bytes little-endian (0xFFFFFFFFFFFFFFFF for unknown)

Parameters:

  • output (IO, StringIO)

    Output stream



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/omnizip/algorithms/lzma/xz_encoder.rb', line 89

def write_header(output)
  # Property byte: (pb * 5 + lp) * 9 + lc
  props = (((@pb * 5) + @lp) * 9) + @lc
  output.putc(props)

  # Dictionary size (4 bytes little-endian)
  4.times do |i|
    output.putc((@dict_size >> (i * 8)) & 0xFF)
  end

  # Uncompressed size (8 bytes little-endian)
  # Use 0xFFFFFFFFFFFFFFFF for unknown size (standard practice)
  # This allows the encoder to use an EOS marker instead of knowing exact size upfront
  size = 0xFFFFFFFFFFFFFFFF
  8.times do |i|
    output.putc((size >> (i * 8)) & 0xFF)
  end

  # Track header bytes in output_total (1 + 4 + 8 = 13 bytes)
  @output_total += 13
end