omnizip 0.3.13 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/omnizip/algorithm.rb +36 -1
- data/lib/omnizip/algorithms/bzip2.rb +1 -3
- data/lib/omnizip/algorithms/deflate.rb +1 -3
- data/lib/omnizip/algorithms/deflate64.rb +2 -2
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +7 -8
- data/lib/omnizip/algorithms/lzma.rb +1 -1
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +5 -1
- data/lib/omnizip/algorithms/lzma2.rb +4 -12
- data/lib/omnizip/algorithms/zstandard/constants.rb +38 -25
- data/lib/omnizip/algorithms/zstandard/decoder.rb +101 -136
- data/lib/omnizip/algorithms/zstandard/encoder.rb +81 -138
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +17 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +42 -29
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +114 -117
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +434 -222
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +98 -176
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +21 -2
- data/lib/omnizip/algorithms/zstandard/huffman.rb +195 -188
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +232 -255
- data/lib/omnizip/algorithms/zstandard/literals.rb +170 -103
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +47 -199
- data/lib/omnizip/algorithms/zstandard/sequences.rb +260 -252
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +20 -24
- data/lib/omnizip/algorithms.rb +14 -1
- data/lib/omnizip/buffer.rb +1 -2
- data/lib/omnizip/commands/archive_list_command.rb +9 -7
- data/lib/omnizip/convenience.rb +1 -2
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/extraction/selective_extractor.rb +2 -10
- data/lib/omnizip/filter_pipeline.rb +1 -1
- data/lib/omnizip/filter_registry.rb +18 -16
- data/lib/omnizip/filters/bcj2.rb +1 -1
- data/lib/omnizip/filters/bcj_arm.rb +1 -1
- data/lib/omnizip/filters/bcj_arm64.rb +1 -1
- data/lib/omnizip/filters/bcj_ia64.rb +1 -1
- data/lib/omnizip/filters/bcj_ppc.rb +1 -1
- data/lib/omnizip/filters/bcj_sparc.rb +1 -1
- data/lib/omnizip/filters/bcj_x86.rb +1 -1
- data/lib/omnizip/filters.rb +0 -2
- data/lib/omnizip/formats/bzip2_file.rb +0 -7
- data/lib/omnizip/formats/cpio/entry.rb +6 -0
- data/lib/omnizip/formats/cpio.rb +0 -6
- data/lib/omnizip/formats/gzip.rb +0 -7
- data/lib/omnizip/formats/iso/directory_record.rb +7 -0
- data/lib/omnizip/formats/iso.rb +0 -5
- data/lib/omnizip/formats/lzip.rb +0 -7
- data/lib/omnizip/formats/lzma_alone.rb +0 -6
- data/lib/omnizip/formats/msi/entry.rb +6 -0
- data/lib/omnizip/formats/msi.rb +0 -9
- data/lib/omnizip/formats/ole/dirent.rb +6 -0
- data/lib/omnizip/formats/ole.rb +0 -9
- data/lib/omnizip/formats/rar.rb +0 -6
- data/lib/omnizip/formats/rar3/reader.rb +7 -0
- data/lib/omnizip/formats/rar5/reader.rb +7 -0
- data/lib/omnizip/formats/rpm/entry.rb +6 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +7 -0
- data/lib/omnizip/formats/seven_zip.rb +0 -6
- data/lib/omnizip/formats/tar/entry.rb +6 -0
- data/lib/omnizip/formats/tar.rb +2 -10
- data/lib/omnizip/formats/xar/entry.rb +6 -0
- data/lib/omnizip/formats/xar.rb +0 -6
- data/lib/omnizip/formats/zip.rb +0 -6
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +33 -31
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +177 -163
- data/lib/omnizip/implementations.rb +18 -4
- data/lib/omnizip/io/source.rb +3 -0
- data/lib/omnizip/metadata/entry_metadata.rb +7 -0
- data/lib/omnizip/parallel/engine.rb +48 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +5 -16
- data/lib/omnizip/parallel/parallel_extractor.rb +5 -16
- data/lib/omnizip/parallel.rb +1 -0
- data/lib/omnizip/profile/profile_registry.rb +1 -2
- data/lib/omnizip/registry.rb +0 -1
- data/lib/omnizip/rubyzip_compat.rb +0 -1
- data/lib/omnizip/temp/temp_file.rb +1 -2
- data/lib/omnizip/version.rb +1 -1
- data/lib/omnizip/zip/entry.rb +7 -0
- data/lib/omnizip/zip/file.rb +4 -8
- data/lib/omnizip.rb +1 -1
- metadata +7 -6
- data/lib/omnizip/filters/filter_base.rb +0 -6
- data/lib/omnizip/filters/registration.rb +0 -22
- data/lib/omnizip/filters/registry.rb +0 -111
- data/lib/omnizip/format_registry.rb +0 -100
|
@@ -23,245 +23,252 @@
|
|
|
23
23
|
module Omnizip
|
|
24
24
|
module Algorithms
|
|
25
25
|
class Zstandard
|
|
26
|
-
# Huffman
|
|
26
|
+
# Huffman coding for Zstandard literals (RFC 8878 §4.2).
|
|
27
27
|
#
|
|
28
|
-
# Zstandard
|
|
29
|
-
#
|
|
28
|
+
# Zstandard does NOT use symbol-ordered canonical Huffman. The
|
|
29
|
+
# decode table groups symbols by weight: all weight-1 symbols
|
|
30
|
+
# occupy the first DTable entries, then weight-2, and so on, with
|
|
31
|
+
# ascending symbol order inside each group. A symbol with weight
|
|
32
|
+
# w has code length (tableLog + 1 - w) and occupies (1 << w) >> 1
|
|
33
|
+
# consecutive DTable entries.
|
|
30
34
|
class Huffman
|
|
31
35
|
include Constants
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
attr_reader :decode_table
|
|
37
|
+
DecodeEntry = Struct.new(:symbol, :nb_bits)
|
|
35
38
|
|
|
36
|
-
# @return [Integer]
|
|
37
|
-
attr_reader :
|
|
39
|
+
# @return [Array<Integer>] per-symbol weights (0 = absent)
|
|
40
|
+
attr_reader :weights
|
|
38
41
|
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
# @param weights [Array<Integer>] Symbol weights (0 means not present)
|
|
42
|
-
# @param max_bits [Integer] Maximum code length
|
|
43
|
-
# @return [Huffman] Built Huffman decoder
|
|
44
|
-
def self.build_from_weights(weights, max_bits = HUFFMAN_MAX_BITS)
|
|
45
|
-
# Convert weights to code lengths
|
|
46
|
-
code_lengths = calculate_code_lengths(weights, max_bits)
|
|
47
|
-
|
|
48
|
-
# Build canonical Huffman codes
|
|
49
|
-
codes = build_canonical_codes(code_lengths)
|
|
50
|
-
|
|
51
|
-
# Build decode table: code -> [symbol, length]
|
|
52
|
-
decode_table = {}
|
|
53
|
-
code_lengths.each_with_index do |length, symbol|
|
|
54
|
-
next if length.nil? || length.zero?
|
|
55
|
-
|
|
56
|
-
code = codes[symbol]
|
|
57
|
-
decode_table[code] = [symbol, length]
|
|
58
|
-
end
|
|
42
|
+
# @return [Integer] table log (max code length in this tree)
|
|
43
|
+
attr_reader :table_log
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
# Build a decode table from per-symbol weights.
|
|
46
|
+
#
|
|
47
|
+
# @param weights [Array<Integer>] one entry per symbol
|
|
48
|
+
# @return [Huffman]
|
|
49
|
+
def self.from_weights(weights)
|
|
50
|
+
table_log = compute_table_log(weights)
|
|
51
|
+
new(weights, table_log)
|
|
61
52
|
end
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
# @param weights [Array<Integer>] Symbol weights
|
|
69
|
-
# @param max_bits [Integer] Maximum code length
|
|
70
|
-
# @return [Array<Integer>] Code lengths
|
|
71
|
-
def self.calculate_code_lengths(weights, max_bits)
|
|
72
|
-
return [] if weights.nil? || weights.empty?
|
|
73
|
-
|
|
74
|
-
# Find max weight
|
|
75
|
-
max_weight = weights.max || 0
|
|
76
|
-
return Array.new(weights.length, 0) if max_weight.zero?
|
|
77
|
-
|
|
78
|
-
# Convert weights to code lengths
|
|
79
|
-
# Higher weight = shorter code length
|
|
80
|
-
weights.map do |weight|
|
|
81
|
-
next 0 if weight.nil? || weight.zero?
|
|
82
|
-
|
|
83
|
-
# Code length = max_weight - weight + 1
|
|
84
|
-
[max_weight - weight + 1, max_bits].min
|
|
85
|
-
end
|
|
54
|
+
def initialize(weights, table_log)
|
|
55
|
+
@weights = weights
|
|
56
|
+
@table_log = table_log
|
|
57
|
+
@lookup = nil
|
|
86
58
|
end
|
|
87
59
|
|
|
88
|
-
#
|
|
60
|
+
# Decode one symbol from a reverse bitstream (peek max_bits,
|
|
61
|
+
# look up, consume the code's length).
|
|
89
62
|
#
|
|
90
|
-
# @param
|
|
91
|
-
# @return [
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# Count symbols at each length
|
|
99
|
-
bl_count = Array.new(max_length + 1, 0)
|
|
100
|
-
code_lengths.each do |length|
|
|
101
|
-
bl_count[length] += 1 if length&.positive?
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Calculate starting code for each length
|
|
105
|
-
code = 0
|
|
106
|
-
next_code = Array.new(max_length + 1, 0)
|
|
107
|
-
(1..max_length).each do |bits|
|
|
108
|
-
code = ((code + bl_count[bits - 1]) << 1)
|
|
109
|
-
next_code[bits] = code
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Assign codes to symbols
|
|
113
|
-
code_lengths.each_with_index do |length, symbol|
|
|
114
|
-
next if length.nil? || length.zero?
|
|
115
|
-
|
|
116
|
-
codes[symbol] = next_code[length]
|
|
117
|
-
next_code[length] += 1
|
|
63
|
+
# @param bitstream [FSE::BitStream]
|
|
64
|
+
# @return [Integer] decoded symbol byte
|
|
65
|
+
def decode(bitstream)
|
|
66
|
+
entry = lookup[bitstream.peek_bits(HUFFMAN_MAX_BITS)]
|
|
67
|
+
if entry.nil? || entry.nb_bits.zero?
|
|
68
|
+
raise Omnizip::DecompressionError,
|
|
69
|
+
"Huffman lookup miss: no code for the next bits"
|
|
118
70
|
end
|
|
119
71
|
|
|
120
|
-
|
|
72
|
+
bitstream.read_bits(entry.nb_bits)
|
|
73
|
+
entry.symbol
|
|
121
74
|
end
|
|
122
75
|
|
|
123
|
-
#
|
|
76
|
+
# Build the flat 1 << HUFFMAN_MAX_BITS lookup table.
|
|
124
77
|
#
|
|
125
|
-
# @
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
78
|
+
# @return [Array<DecodeEntry>]
|
|
79
|
+
def lookup
|
|
80
|
+
@lookup ||= begin
|
|
81
|
+
table_size = 1 << @table_log
|
|
82
|
+
dtable = Array.new(table_size) { DecodeEntry.new(0, 0) }
|
|
83
|
+
max_weight = @weights.max || 0
|
|
84
|
+
|
|
85
|
+
pos = 0
|
|
86
|
+
(1..max_weight).each do |w|
|
|
87
|
+
length = @table_log + 1 - w
|
|
88
|
+
entries_per_symbol = (1 << w) >> 1
|
|
89
|
+
@weights.each_with_index do |sw, sym|
|
|
90
|
+
next unless sw == w
|
|
91
|
+
|
|
92
|
+
entry = DecodeEntry.new(sym, length)
|
|
93
|
+
entries_per_symbol.times do
|
|
94
|
+
if pos < table_size
|
|
95
|
+
dtable[pos] = entry
|
|
96
|
+
pos += 1
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
expand = 1 << (HUFFMAN_MAX_BITS - @table_log)
|
|
103
|
+
lookup = []
|
|
104
|
+
table_size.times do |i|
|
|
105
|
+
expand.times { lookup << dtable[i] }
|
|
106
|
+
end
|
|
107
|
+
while lookup.length < (1 << HUFFMAN_MAX_BITS)
|
|
108
|
+
lookup << DecodeEntry.new(0, 0)
|
|
109
|
+
end
|
|
110
|
+
lookup
|
|
111
|
+
end
|
|
133
112
|
end
|
|
134
113
|
|
|
135
|
-
#
|
|
114
|
+
# Per-symbol (code, length) table for encoding, indexed by
|
|
115
|
+
# symbol value. Absent symbols map to (0, 0).
|
|
136
116
|
#
|
|
137
|
-
# @
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if @decode_table.key?(code)
|
|
153
|
-
expected_length = @decode_table[code][1]
|
|
154
|
-
if bits_read == expected_length
|
|
155
|
-
return @decode_table[code][0]
|
|
117
|
+
# @return [Array<Array(Integer, Integer)>]
|
|
118
|
+
def encode_table
|
|
119
|
+
@encode_table ||= begin
|
|
120
|
+
codes = Array.new(@weights.length) { [0, 0] }
|
|
121
|
+
max_weight = @weights.max || 0
|
|
122
|
+
dtable_pos = 0
|
|
123
|
+
(1..max_weight).each do |w|
|
|
124
|
+
length = @table_log + 1 - w
|
|
125
|
+
entries_per_symbol = (1 << w) >> 1
|
|
126
|
+
@weights.each_with_index do |sw, sym|
|
|
127
|
+
next unless sw == w
|
|
128
|
+
|
|
129
|
+
code = dtable_pos >> (@table_log - length)
|
|
130
|
+
codes[sym] = [code, length]
|
|
131
|
+
dtable_pos += entries_per_symbol
|
|
156
132
|
end
|
|
157
133
|
end
|
|
134
|
+
codes.fill([0, 0], codes.length..255)
|
|
135
|
+
codes
|
|
158
136
|
end
|
|
159
|
-
|
|
160
|
-
# Fallback: try lookup table
|
|
161
|
-
symbol = @lookup_table[code]
|
|
162
|
-
return symbol if symbol
|
|
163
|
-
|
|
164
|
-
0
|
|
165
137
|
end
|
|
166
138
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
#
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
139
|
+
# Derive tableLog from the Kraft sum of the weights
|
|
140
|
+
# (C reference HUF_readStats).
|
|
141
|
+
#
|
|
142
|
+
# @return [Integer]
|
|
143
|
+
def self.compute_table_log(weights)
|
|
144
|
+
if weights.empty? || weights.all?(0)
|
|
145
|
+
raise Omnizip::DecompressionError,
|
|
146
|
+
"Huffman weights: no present symbols"
|
|
147
|
+
end
|
|
174
148
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
149
|
+
weight_total = weights.sum { |w| w.positive? ? (1 << w) >> 1 : 0 }
|
|
150
|
+
if weight_total.zero?
|
|
151
|
+
raise Omnizip::DecompressionError, "Huffman weight total is 0"
|
|
152
|
+
end
|
|
179
153
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
154
|
+
table_log = if weight_total.nobits?(weight_total - 1)
|
|
155
|
+
Constants.highbit32(weight_total)
|
|
156
|
+
else
|
|
157
|
+
Constants.highbit32(weight_total) + 1
|
|
158
|
+
end
|
|
159
|
+
if table_log > HUFFMAN_MAX_BITS
|
|
160
|
+
raise Omnizip::DecompressionError,
|
|
161
|
+
"Huffman tableLog #{table_log} exceeds max #{HUFFMAN_MAX_BITS}"
|
|
184
162
|
end
|
|
185
|
-
end
|
|
186
163
|
|
|
187
|
-
|
|
188
|
-
def read_single_bit_forward(bitstream)
|
|
189
|
-
bitstream.read_bits(1)
|
|
164
|
+
table_log
|
|
190
165
|
end
|
|
191
166
|
end
|
|
192
167
|
|
|
193
|
-
# Huffman
|
|
194
|
-
#
|
|
195
|
-
# Reads compressed Huffman table description from input.
|
|
168
|
+
# Reads a Huffman tree description from the wire (RFC 8878
|
|
169
|
+
# §4.2.1) and builds a Huffman decode table.
|
|
196
170
|
class HuffmanTableReader
|
|
197
171
|
include Constants
|
|
198
172
|
|
|
199
|
-
# Read
|
|
173
|
+
# Read the table from the head of `src`.
|
|
200
174
|
#
|
|
201
|
-
# @param
|
|
202
|
-
# @return [Huffman]
|
|
203
|
-
def self.read(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
175
|
+
# @param src [String]
|
|
176
|
+
# @return [Array(Huffman, Integer)] table and bytes consumed
|
|
177
|
+
def self.read(src)
|
|
178
|
+
raise Omnizip::DecompressionError, "empty Huffman header" if src.empty?
|
|
179
|
+
|
|
180
|
+
i_size = src.getbyte(0)
|
|
181
|
+
weights, consumed =
|
|
182
|
+
if i_size >= 128
|
|
183
|
+
read_direct_weights(src)
|
|
184
|
+
else
|
|
185
|
+
read_fse_compressed_weights(src)
|
|
186
|
+
end
|
|
207
187
|
|
|
208
|
-
|
|
209
|
-
@input = input
|
|
188
|
+
[Huffman.from_weights(weights), consumed]
|
|
210
189
|
end
|
|
211
190
|
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if fse_compressed
|
|
223
|
-
read_fse_compressed_weights(header)
|
|
224
|
-
else
|
|
225
|
-
read_raw_weights(header)
|
|
191
|
+
# Direct 4-bit weights: byte 0 is 127 + o_size, then
|
|
192
|
+
# (o_size + 1) / 2 bytes holding two nibbles each.
|
|
193
|
+
def self.read_direct_weights(src)
|
|
194
|
+
i_size = src.getbyte(0)
|
|
195
|
+
o_size = i_size - 127
|
|
196
|
+
packed_bytes = (o_size + 1) / 2
|
|
197
|
+
needed = 1 + packed_bytes
|
|
198
|
+
if src.bytesize < needed
|
|
199
|
+
raise Omnizip::DecompressionError,
|
|
200
|
+
"truncated direct Huffman weights: need #{needed} bytes"
|
|
226
201
|
end
|
|
227
|
-
end
|
|
228
202
|
|
|
229
|
-
|
|
203
|
+
weights = []
|
|
204
|
+
(0...o_size).step(2) do |n|
|
|
205
|
+
byte = src.getbyte(1 + (n / 2))
|
|
206
|
+
weights << (byte >> 4)
|
|
207
|
+
weights << (byte & 0x0F) if n + 1 < o_size
|
|
208
|
+
end
|
|
230
209
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
(header & 0x1F) + 5
|
|
210
|
+
weights << implied_last_weight(weights)
|
|
211
|
+
[weights, needed]
|
|
212
|
+
end
|
|
235
213
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
214
|
+
# FSE-compressed weights: byte 0 is the payload size, followed
|
|
215
|
+
# by an FSE table description and a 2-state interleaved
|
|
216
|
+
# bitstream (RFC 8878 §4.2.1.2).
|
|
217
|
+
def self.read_fse_compressed_weights(src)
|
|
218
|
+
i_size = src.getbyte(0)
|
|
219
|
+
if 1 + i_size > src.bytesize
|
|
220
|
+
raise Omnizip::DecompressionError,
|
|
221
|
+
"truncated FSE Huffman weights: need #{1 + i_size} bytes"
|
|
222
|
+
end
|
|
239
223
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
224
|
+
payload = src.byteslice(1, i_size)
|
|
225
|
+
table, consumed = FSE.read_table(payload)
|
|
226
|
+
bitstream = payload.byteslice(consumed..)
|
|
243
227
|
|
|
244
|
-
|
|
245
|
-
|
|
228
|
+
weights = FSE.decode_stream(table, bitstream, HUF_SYMBOLVALUE_MAX)
|
|
229
|
+
weights << implied_last_weight(weights)
|
|
230
|
+
[weights, 1 + i_size]
|
|
246
231
|
end
|
|
247
232
|
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
233
|
+
# Compute the implied last weight via the Kraft inequality:
|
|
234
|
+
# sum(2^(w-1)) over all symbols equals 1 << tableLog.
|
|
235
|
+
def self.implied_last_weight(weights)
|
|
236
|
+
weight_total = 0
|
|
237
|
+
weights.each do |w|
|
|
238
|
+
if w > HUFFMAN_MAX_LOG
|
|
239
|
+
raise Omnizip::DecompressionError,
|
|
240
|
+
"Huffman weight #{w} exceeds tableLog max"
|
|
241
|
+
end
|
|
253
242
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
243
|
+
weight_total += (1 << w) >> 1
|
|
244
|
+
end
|
|
245
|
+
if weight_total.zero?
|
|
246
|
+
raise Omnizip::DecompressionError, "Huffman weights sum to 0"
|
|
247
|
+
end
|
|
257
248
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
249
|
+
table_log = Constants.highbit32(weight_total) + 1
|
|
250
|
+
if table_log > HUFFMAN_MAX_LOG
|
|
251
|
+
raise Omnizip::DecompressionError,
|
|
252
|
+
"Huffman tableLog #{table_log} exceeds max"
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
rest = (1 << table_log) - weight_total
|
|
256
|
+
if rest.zero?
|
|
257
|
+
raise Omnizip::DecompressionError,
|
|
258
|
+
"Huffman weights already complete; no implied weight"
|
|
259
|
+
end
|
|
260
|
+
unless rest.nobits?(rest - 1)
|
|
261
|
+
raise Omnizip::DecompressionError,
|
|
262
|
+
"Huffman implied weight remainder #{rest} is not a power of 2"
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
last_weight = Constants.highbit32(rest) + 1
|
|
266
|
+
if last_weight > HUFFMAN_MAX_LOG
|
|
267
|
+
raise Omnizip::DecompressionError,
|
|
268
|
+
"Huffman implied weight #{last_weight} exceeds max"
|
|
262
269
|
end
|
|
263
270
|
|
|
264
|
-
|
|
271
|
+
last_weight
|
|
265
272
|
end
|
|
266
273
|
end
|
|
267
274
|
end
|