Class: Omnizip::Formats::SevenZip::StreamCompressor

Inherits:
Object
  • Object
show all
Defined in:
lib/omnizip/formats/seven_zip/stream_compressor.rb

Overview

Compresses data streams using coder chains Opposite of StreamDecompressor - applies compression algorithms

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(algorithm: :lzma2, level: 5, filters: []) ⇒ StreamCompressor

Initialize compressor

Parameters:

  • algorithm (Symbol) (defaults to: :lzma2)

    Compression algorithm

  • level (Integer) (defaults to: 5)

    Compression level (1-9)

  • filters (Array<Symbol>) (defaults to: [])

    Filter chain



18
19
20
21
22
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 18

def initialize(algorithm: :lzma2, level: 5, filters: [])
  @algorithm = algorithm
  @level = level
  @filters = Array(filters)
end

Instance Attribute Details

#algorithmObject (readonly)

Returns the value of attribute algorithm.



11
12
13
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 11

def algorithm
  @algorithm
end

#filtersObject (readonly)

Returns the value of attribute filters.



11
12
13
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 11

def filters
  @filters
end

#levelObject (readonly)

Returns the value of attribute level.



11
12
13
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 11

def level
  @level
end

Instance Method Details

#compress(data) ⇒ String

Compress data

Parameters:

  • data (String)

    Uncompressed data

Returns:

  • (String)

    Compressed data



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 28

def compress(data)
  result = data

  # Apply filters first
  @filters.each do |filter_sym|
    filter_class = FilterRegistry.get(filter_sym)
    next unless filter_class

    filter = filter_class.new
    input_io = StringIO.new(result)
    output_io = StringIO.new
    output_io.set_encoding("BINARY")
    filter.encode(input_io, output_io)
    result = output_io.string
  end

  # Apply compression algorithm
  if @algorithm && @algorithm != :copy
    algo_class = Omnizip::AlgorithmRegistry.get(@algorithm)
    raise "Algorithm not found: #{@algorithm}" unless algo_class

    encoder = algo_class.new
    input_io = StringIO.new(result)
    output_io = StringIO.new
    output_io.set_encoding("BINARY")

    # For 7-Zip format, use raw_mode (no property byte in compressed data)
    # The properties are encoded in the 7-Zip header instead
    encoder.compress(input_io, output_io,
                     { raw_mode: true, standalone: false })
    result = output_io.string
  end

  result
end

#compress_files(file_entries) ⇒ Hash

Compress multiple files into single stream (solid compression)

Parameters:

Returns:

  • (Hash)

    Compression result with packed/unpacked sizes



68
69
70
71
72
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
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 68

def compress_files(file_entries)
  # Concatenate all file data
  combined_data = String.new(encoding: "BINARY")
  unpack_sizes = []
  crcs = []

  file_entries.each do |entry|
    next unless entry.has_stream? && entry.source_path

    data = File.binread(entry.source_path)
    combined_data << data
    unpack_sizes << data.bytesize

    # Calculate CRC
    crc = Omnizip::Checksums::Crc32.new
    crc.update(data)
    crcs << crc.value
  end

  # Compress combined data
  packed_data = compress(combined_data)

  {
    packed_data: packed_data,
    packed_size: packed_data.bytesize,
    unpack_size: combined_data.bytesize,
    unpack_sizes: unpack_sizes,
    crcs: crcs,
  }
end

#filter_idsArray<Integer>

Get filter IDs for filter chain

Returns:

  • (Array<Integer>)

    Filter IDs



116
117
118
119
120
121
122
123
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 116

def filter_ids
  @filters.filter_map do |filter_sym|
    case filter_sym
    when :bcj_x86 then Constants::FilterId::BCJ_X86
    when :delta then Constants::FilterId::DELTA
    end
  end
end

#method_idInteger

Get method ID for this compression algorithm

Returns:

  • (Integer)

    Method ID



102
103
104
105
106
107
108
109
110
111
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 102

def method_id
  case @algorithm
  when :copy then Constants::MethodId::COPY
  when :lzma then Constants::MethodId::LZMA
  when :lzma2 then Constants::MethodId::LZMA2
  when :ppmd, :ppmd7 then Constants::MethodId::PPMD
  when :bzip2 then Constants::MethodId::BZIP2
  else Constants::MethodId::LZMA2
  end
end

#propertiesString?

Get properties for compression algorithm

Returns:

  • (String, nil)

    Binary properties



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/omnizip/formats/seven_zip/stream_compressor.rb', line 128

def properties
  return nil if @algorithm == :copy || @algorithm.nil?

  case @algorithm
  when :lzma2
    # LZMA2 properties: dictionary size encoded
    dict_size = 1 << (15 + @level)
    prop = 0
    prop += 1 while dict_size > (2 << prop)
    [prop].pack("C")
  when :lzma
    # LZMA properties: lc, lp, pb, dict_size
    lc = 3
    lp = 0
    pb = 2
    dict_size = 1 << (15 + @level)
    [lc + (lp * 9) + (pb * 9 * 5)].pack("C") +
      [dict_size].pack("V")
  end
end