Class: Omnizip::Formats::SevenZip::CoderChain

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/omnizip/formats/seven_zip/coder_chain.rb

Overview

Builds coder chains from .7z folder specifications Maps method IDs to algorithms and filters, reconstructing the decompression pipeline

Constant Summary

Constants included from Constants

Omnizip::Formats::SevenZip::Constants::MAJOR_VERSION, Omnizip::Formats::SevenZip::Constants::MAX_NUM_BONDS, Omnizip::Formats::SevenZip::Constants::MAX_NUM_CODERS, Omnizip::Formats::SevenZip::Constants::MAX_NUM_PACK_STREAMS, Omnizip::Formats::SevenZip::Constants::MINOR_VERSION, Omnizip::Formats::SevenZip::Constants::SIGNATURE, Omnizip::Formats::SevenZip::Constants::SIGNATURE_SIZE, Omnizip::Formats::SevenZip::Constants::START_HEADER_SIZE

Class Method Summary collapse

Class Method Details

.algorithm_for_method(method_id) ⇒ Symbol

Map method ID to algorithm

Parameters:

  • method_id (Integer)

    Method ID from .7z file

Returns:

  • (Symbol)

    Algorithm identifier

Raises:

  • (RuntimeError)

    if method not supported



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/omnizip/formats/seven_zip/coder_chain.rb', line 68

def self.algorithm_for_method(method_id)
  case method_id
  when MethodId::COPY
    nil # No decompression needed
  when MethodId::LZMA
    :lzma
  when MethodId::LZMA2
    :lzma2
  when MethodId::PPMD
    :ppmd7
  when MethodId::BZIP2
    :bzip2
  when MethodId::DEFLATE
    :deflate
  when MethodId::DEFLATE64
    :deflate64
  else
    raise "Unsupported compression method: " \
          "0x#{method_id.to_s(16)}"
  end
end

.build_from_folder(folder) ⇒ Hash

Build coder chain from folder specification

Parameters:

Returns:

  • (Hash)

    Coder chain configuration

Raises:

  • (RuntimeError)

    if unsupported method encountered



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/omnizip/formats/seven_zip/coder_chain.rb', line 17

def self.build_from_folder(folder)
  return nil if folder.coders.empty?

  # Find the compression method (not a filter) among coders
  # Filters like BCJ, BCJ2 have specific method IDs
  main_coder = find_compression_coder(folder.coders)
  raise "No compression method found in folder" unless main_coder

  algorithm = algorithm_for_method(main_coder.method_id)

  # Check for filters (all coders except the compression method)
  filters = []
  folder.coders.each do |coder|
    next if coder == main_coder

    filter = filter_for_method(coder.method_id)
    filters << filter if filter
  end

  {
    algorithm: algorithm,
    filters: filters,
    properties: main_coder.properties,
    unpack_size: folder.unpack_sizes.last,
  }
end

.create_decompressor(chain_config, input_io) ⇒ Object

Create decompressor for coder chain

Parameters:

  • chain_config (Hash)

    Chain configuration

  • input_io (IO)

    Input stream

Returns:

  • (Object)

    Decompressor instance



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/omnizip/formats/seven_zip/coder_chain.rb', line 122

def self.create_decompressor(chain_config, input_io)
  return nil unless chain_config
  return input_io unless chain_config[:algorithm]

  # Get algorithm
  algo_class = AlgorithmRegistry.get(chain_config[:algorithm])
  unless algo_class
    raise "Algorithm not found: #{chain_config[:algorithm]}"
  end

  # Create algorithm instance
  decompressor = algo_class.new
  # Pass properties if algorithm supports them
  # Some algorithms (LZMA2) need properties
  if chain_config[:properties] && !chain_config[:properties].empty? && decompressor.is_a?(Omnizip::Algorithms::LZMA2)
    decompressor.properties = chain_config[:properties]
  end

  # Apply filters if present
  if chain_config[:filters] && !chain_config[:filters].empty?
    # Build filter pipeline
    pipeline = FilterPipeline.new
    chain_config[:filters].each do |filter_sym|
      filter_class = FilterRegistry.get(filter_sym)
      raise "Filter not found: #{filter_sym}" unless filter_class

      pipeline.add_filter(filter_class.new)
    end

    # Return composite: input -> algorithm -> filters
    {
      decompressor: decompressor,
      pipeline: pipeline,
      input: input_io,
    }
  else
    # Just algorithm
    {
      decompressor: decompressor,
      pipeline: nil,
      input: input_io,
    }
  end
end

.filter_for_method(method_id) ⇒ Symbol?

Map method ID to filter

Parameters:

  • method_id (Integer)

    Method ID from .7z file

Returns:

  • (Symbol, nil)

    Filter identifier or nil



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/omnizip/formats/seven_zip/coder_chain.rb', line 94

def self.filter_for_method(method_id)
  case method_id
  when FilterId::BCJ_X86
    :bcj_x86
  when FilterId::BCJ_PPC
    :bcj_ppc
  when FilterId::BCJ_IA64
    :bcj_ia64
  when FilterId::BCJ_ARM
    :bcj_arm
  when FilterId::BCJ_ARMT
    :bcj_armt
  when FilterId::BCJ_SPARC
    :bcj_sparc
  when FilterId::ARM64
    :bcj_arm64
  when FilterId::DELTA
    :delta
  when FilterId::BCJ2
    :bcj2
  end
end

.find_compression_coder(coders) ⇒ Models::CoderInfo?

Find the compression coder among all coders

Parameters:

Returns:



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/omnizip/formats/seven_zip/coder_chain.rb', line 48

def self.find_compression_coder(coders)
  # Try to find a known compression method
  coders.each do |coder|
    case coder.method_id
    when MethodId::LZMA, MethodId::LZMA2, MethodId::BZIP2,
         MethodId::DEFLATE, MethodId::DEFLATE64, MethodId::PPMD,
         MethodId::COPY
      return coder
    end
  end

  # Fall back to last coder if no known compression method found
  coders.last
end