/src/libjxl/lib/jxl/dec_ans.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #include "lib/jxl/dec_ans.h" |
7 | | |
8 | | #include <jxl/memory_manager.h> |
9 | | |
10 | | #include <algorithm> |
11 | | #include <cstddef> |
12 | | #include <cstdint> |
13 | | #include <utility> |
14 | | #include <vector> |
15 | | |
16 | | #include "lib/jxl/ans_common.h" |
17 | | #include "lib/jxl/ans_params.h" |
18 | | #include "lib/jxl/base/bits.h" |
19 | | #include "lib/jxl/base/compiler_specific.h" |
20 | | #include "lib/jxl/base/printf_macros.h" |
21 | | #include "lib/jxl/base/status.h" |
22 | | #include "lib/jxl/dec_bit_reader.h" |
23 | | #include "lib/jxl/dec_context_map.h" |
24 | | #include "lib/jxl/dec_huffman.h" |
25 | | #include "lib/jxl/field_encodings.h" |
26 | | #include "lib/jxl/fields.h" |
27 | | #include "lib/jxl/memory_manager_internal.h" |
28 | | |
29 | | namespace jxl { |
30 | | namespace { |
31 | | |
32 | | // Decodes a number in the range [0..255], by reading 1 - 11 bits. |
33 | 59.6k | inline int DecodeVarLenUint8(BitReader* input) { |
34 | 59.6k | if (input->ReadFixedBits<1>()) { |
35 | 18.3k | int nbits = static_cast<int>(input->ReadFixedBits<3>()); |
36 | 18.3k | if (nbits == 0) { |
37 | 6.31k | return 1; |
38 | 12.0k | } else { |
39 | 12.0k | return static_cast<int>(input->ReadBits(nbits)) + (1 << nbits); |
40 | 12.0k | } |
41 | 18.3k | } |
42 | 41.3k | return 0; |
43 | 59.6k | } |
44 | | |
45 | | // Decodes a number in the range [0..65535], by reading 1 - 21 bits. |
46 | 53.7k | inline int DecodeVarLenUint16(BitReader* input) { |
47 | 53.7k | if (input->ReadFixedBits<1>()) { |
48 | 3.27k | int nbits = static_cast<int>(input->ReadFixedBits<4>()); |
49 | 3.27k | if (nbits == 0) { |
50 | 207 | return 1; |
51 | 3.06k | } else { |
52 | 3.06k | return static_cast<int>(input->ReadBits(nbits)) + (1 << nbits); |
53 | 3.06k | } |
54 | 3.27k | } |
55 | 50.4k | return 0; |
56 | 53.7k | } |
57 | | |
58 | | Status ReadHistogram(int precision_bits, std::vector<int32_t>* counts, |
59 | 54.6k | BitReader* input) { |
60 | 54.6k | int range = 1 << precision_bits; |
61 | 54.6k | int simple_code = input->ReadBits(1); |
62 | 54.6k | if (simple_code == 1) { |
63 | 11.8k | int i; |
64 | 11.8k | int symbols[2] = {0}; |
65 | 11.8k | int max_symbol = 0; |
66 | 11.8k | const int num_symbols = input->ReadBits(1) + 1; |
67 | 25.9k | for (i = 0; i < num_symbols; ++i) { |
68 | 14.1k | symbols[i] = DecodeVarLenUint8(input); |
69 | 14.1k | if (symbols[i] > max_symbol) max_symbol = symbols[i]; |
70 | 14.1k | } |
71 | 11.8k | counts->resize(max_symbol + 1); |
72 | 11.8k | if (num_symbols == 1) { |
73 | 9.59k | (*counts)[symbols[0]] = range; |
74 | 9.59k | } else { |
75 | 2.26k | if (symbols[0] == symbols[1]) { // corrupt data |
76 | 53 | return false; |
77 | 53 | } |
78 | 2.21k | (*counts)[symbols[0]] = input->ReadBits(precision_bits); |
79 | 2.21k | (*counts)[symbols[1]] = range - (*counts)[symbols[0]]; |
80 | 2.21k | } |
81 | 42.7k | } else { |
82 | 42.7k | int is_flat = input->ReadBits(1); |
83 | 42.7k | if (is_flat == 1) { |
84 | 15.0k | int alphabet_size = DecodeVarLenUint8(input) + 1; |
85 | 15.0k | JXL_ENSURE(alphabet_size <= range); |
86 | 15.0k | *counts = CreateFlatHistogram(alphabet_size, range); |
87 | 15.0k | return true; |
88 | 15.0k | } |
89 | | |
90 | 27.6k | uint32_t shift; |
91 | 27.6k | { |
92 | | // TODO(veluca): speed up reading with table lookups. |
93 | 27.6k | int upper_bound_log = FloorLog2Nonzero(ANS_LOG_TAB_SIZE + 1); |
94 | 27.6k | int log = 0; |
95 | 33.7k | for (; log < upper_bound_log; log++) { |
96 | 33.3k | if (input->ReadFixedBits<1>() == 0) break; |
97 | 33.3k | } |
98 | 27.6k | shift = (input->ReadBits(log) | (1 << log)) - 1; |
99 | 27.6k | if (shift > ANS_LOG_TAB_SIZE + 1) { |
100 | 10 | return JXL_FAILURE("Invalid shift value"); |
101 | 10 | } |
102 | 27.6k | } |
103 | | |
104 | 27.6k | int length = DecodeVarLenUint8(input) + 3; |
105 | 27.6k | counts->resize(length); |
106 | 27.6k | int total_count = 0; |
107 | | |
108 | 27.6k | static const uint8_t huff[128][2] = { |
109 | 27.6k | {3, 10}, {7, 12}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
110 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
111 | 27.6k | {3, 10}, {5, 0}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
112 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
113 | 27.6k | {3, 10}, {6, 11}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
114 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
115 | 27.6k | {3, 10}, {5, 0}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
116 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
117 | 27.6k | {3, 10}, {7, 13}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
118 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
119 | 27.6k | {3, 10}, {5, 0}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
120 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
121 | 27.6k | {3, 10}, {6, 11}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
122 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
123 | 27.6k | {3, 10}, {5, 0}, {3, 7}, {4, 3}, {3, 6}, {3, 8}, {3, 9}, {4, 5}, |
124 | 27.6k | {3, 10}, {4, 4}, {3, 7}, {4, 1}, {3, 6}, {3, 8}, {3, 9}, {4, 2}, |
125 | 27.6k | }; |
126 | | |
127 | 27.6k | std::vector<int> logcounts(counts->size()); |
128 | 27.6k | int omit_log = -1; |
129 | 27.6k | int omit_pos = -1; |
130 | | // This array remembers which symbols have an RLE length. |
131 | 27.6k | std::vector<int> same(counts->size(), 0); |
132 | 185k | for (size_t i = 0; i < logcounts.size(); ++i) { |
133 | 158k | input->Refill(); // for PeekFixedBits + Advance |
134 | 158k | int idx = input->PeekFixedBits<7>(); |
135 | 158k | input->Consume(huff[idx][0]); |
136 | 158k | logcounts[i] = huff[idx][1]; |
137 | | // The RLE symbol. |
138 | 158k | if (logcounts[i] == ANS_LOG_TAB_SIZE + 1) { |
139 | 2.82k | int rle_length = DecodeVarLenUint8(input); |
140 | 2.82k | same[i] = rle_length + 5; |
141 | 2.82k | i += rle_length + 3; |
142 | 2.82k | continue; |
143 | 2.82k | } |
144 | 155k | if (logcounts[i] > omit_log) { |
145 | 34.9k | omit_log = logcounts[i]; |
146 | 34.9k | omit_pos = i; |
147 | 34.9k | } |
148 | 155k | } |
149 | | // Invalid input, e.g. due to invalid usage of RLE. |
150 | 27.6k | if (omit_pos < 0) return JXL_FAILURE("Invalid histogram."); |
151 | 27.6k | if (static_cast<size_t>(omit_pos) + 1 < logcounts.size() && |
152 | 27.6k | logcounts[omit_pos + 1] == ANS_LOG_TAB_SIZE + 1) { |
153 | 10 | return JXL_FAILURE("Invalid histogram."); |
154 | 10 | } |
155 | 27.6k | int prev = 0; |
156 | 27.6k | int numsame = 0; |
157 | 209k | for (size_t i = 0; i < logcounts.size(); ++i) { |
158 | 181k | if (same[i]) { |
159 | | // RLE sequence, let this loop output the same count for the next |
160 | | // iterations. |
161 | 2.77k | numsame = same[i] - 1; |
162 | 2.77k | prev = i > 0 ? (*counts)[i - 1] : 0; |
163 | 2.77k | } |
164 | 181k | if (numsame > 0) { |
165 | 26.5k | (*counts)[i] = prev; |
166 | 26.5k | numsame--; |
167 | 155k | } else { |
168 | 155k | unsigned int code = logcounts[i]; |
169 | | // omit_pos may not be negative at this point (checked before). |
170 | 155k | if (i == static_cast<size_t>(omit_pos)) { |
171 | 27.6k | continue; |
172 | 127k | } else if (code == 0) { |
173 | 19.3k | continue; |
174 | 108k | } else if (code == 1) { |
175 | 2.17k | (*counts)[i] = 1; |
176 | 106k | } else { |
177 | 106k | int bitcount = GetPopulationCountPrecision(code - 1, shift); |
178 | 106k | (*counts)[i] = (1u << (code - 1)) + |
179 | 106k | (input->ReadBits(bitcount) << (code - 1 - bitcount)); |
180 | 106k | } |
181 | 155k | } |
182 | 134k | total_count += (*counts)[i]; |
183 | 134k | } |
184 | 27.6k | (*counts)[omit_pos] = range - total_count; |
185 | 27.6k | if ((*counts)[omit_pos] <= 0) { |
186 | | // The histogram we've read sums to more than total_count (including at |
187 | | // least 1 for the omitted value). |
188 | 212 | return JXL_FAILURE("Invalid histogram count."); |
189 | 212 | } |
190 | 27.6k | } |
191 | 39.2k | return true; |
192 | 54.6k | } |
193 | | |
194 | | } // namespace |
195 | | |
196 | | Status DecodeANSCodes(JxlMemoryManager* memory_manager, |
197 | | const size_t num_histograms, |
198 | | const size_t max_alphabet_size, BitReader* in, |
199 | 84.7k | ANSCode* result) { |
200 | 84.7k | result->memory_manager = memory_manager; |
201 | 84.7k | result->degenerate_symbols.resize(num_histograms, -1); |
202 | 84.7k | if (result->use_prefix_code) { |
203 | 42.4k | JXL_ENSURE(max_alphabet_size <= 1 << PREFIX_MAX_BITS); |
204 | 42.4k | result->huffman_data.resize(num_histograms); |
205 | 42.4k | std::vector<uint16_t> alphabet_sizes(num_histograms); |
206 | 96.1k | for (size_t c = 0; c < num_histograms; c++) { |
207 | 53.7k | alphabet_sizes[c] = DecodeVarLenUint16(in) + 1; |
208 | 53.7k | if (alphabet_sizes[c] > max_alphabet_size) { |
209 | 34 | return JXL_FAILURE("Alphabet size is too long: %u", alphabet_sizes[c]); |
210 | 34 | } |
211 | 53.7k | } |
212 | 94.7k | for (size_t c = 0; c < num_histograms; c++) { |
213 | 52.9k | if (alphabet_sizes[c] > 1) { |
214 | 2.83k | if (!result->huffman_data[c].ReadFromBitStream(alphabet_sizes[c], in)) { |
215 | 583 | if (!in->AllReadsWithinBounds()) { |
216 | 426 | return JXL_NOT_ENOUGH_BYTES("Not enough bytes for huffman code"); |
217 | 426 | } |
218 | 157 | return JXL_FAILURE("Invalid huffman tree number %" PRIuS |
219 | 583 | ", alphabet size %u", |
220 | 583 | c, alphabet_sizes[c]); |
221 | 583 | } |
222 | 50.0k | } else { |
223 | | // 0-bit codes does not require extension tables. |
224 | 50.0k | result->huffman_data[c].table_.clear(); |
225 | 50.0k | result->huffman_data[c].table_.resize(1u << kHuffmanTableBits); |
226 | 50.0k | } |
227 | 14.8M | for (const auto& h : result->huffman_data[c].table_) { |
228 | 14.8M | if (h.bits <= kHuffmanTableBits) { |
229 | 14.8M | result->UpdateMaxNumBits(c, h.value); |
230 | 14.8M | } |
231 | 14.8M | } |
232 | 52.3k | } |
233 | 42.3k | } else { |
234 | 42.2k | JXL_ENSURE(max_alphabet_size <= ANS_MAX_ALPHABET_SIZE); |
235 | 42.2k | size_t alloc_size = num_histograms * (1 << result->log_alpha_size) * |
236 | 42.2k | sizeof(AliasTable::Entry); |
237 | 42.2k | JXL_ASSIGN_OR_RETURN(result->alias_tables, |
238 | 42.2k | AlignedMemory::Create(memory_manager, alloc_size)); |
239 | 42.2k | AliasTable::Entry* alias_tables = |
240 | 42.2k | result->alias_tables.address<AliasTable::Entry>(); |
241 | 96.5k | for (size_t c = 0; c < num_histograms; ++c) { |
242 | 54.6k | std::vector<int32_t> counts; |
243 | 54.6k | if (!ReadHistogram(ANS_LOG_TAB_SIZE, &counts, in)) { |
244 | 295 | return JXL_FAILURE("Invalid histogram bitstream."); |
245 | 295 | } |
246 | 54.3k | if (counts.size() > max_alphabet_size) { |
247 | 53 | return JXL_FAILURE("Alphabet size is too long: %" PRIuS, counts.size()); |
248 | 53 | } |
249 | 64.7k | while (!counts.empty() && counts.back() == 0) { |
250 | 10.5k | counts.pop_back(); |
251 | 10.5k | } |
252 | 604k | for (size_t s = 0; s < counts.size(); s++) { |
253 | 549k | if (counts[s] != 0) { |
254 | 342k | result->UpdateMaxNumBits(c, s); |
255 | 342k | } |
256 | 549k | } |
257 | | // InitAliasTable "fixes" empty counts to contain degenerate "0" symbol. |
258 | 54.2k | int degenerate_symbol = counts.empty() ? 0 : (counts.size() - 1); |
259 | 110k | for (int s = 0; s < degenerate_symbol; ++s) { |
260 | 87.6k | if (counts[s] != 0) { |
261 | 31.8k | degenerate_symbol = -1; |
262 | 31.8k | break; |
263 | 31.8k | } |
264 | 87.6k | } |
265 | 54.2k | result->degenerate_symbols[c] = degenerate_symbol; |
266 | 54.2k | JXL_RETURN_IF_ERROR( |
267 | 54.2k | InitAliasTable(counts, ANS_LOG_TAB_SIZE, result->log_alpha_size, |
268 | 54.2k | alias_tables + c * (1 << result->log_alpha_size))); |
269 | 54.2k | } |
270 | 42.2k | } |
271 | 83.7k | return true; |
272 | 84.7k | } |
273 | | Status DecodeUintConfig(size_t log_alpha_size, HybridUintConfig* uint_config, |
274 | 120k | BitReader* br) { |
275 | 120k | br->Refill(); |
276 | 120k | size_t split_exponent = br->ReadBits(CeilLog2Nonzero(log_alpha_size + 1)); |
277 | 120k | size_t msb_in_token = 0; |
278 | 120k | size_t lsb_in_token = 0; |
279 | 120k | if (split_exponent != log_alpha_size) { |
280 | | // otherwise, msb/lsb don't matter. |
281 | 106k | size_t nbits = CeilLog2Nonzero(split_exponent + 1); |
282 | 106k | msb_in_token = br->ReadBits(nbits); |
283 | 106k | if (msb_in_token > split_exponent) { |
284 | | // This could be invalid here already and we need to check this before |
285 | | // we use its value to read more bits. |
286 | 82 | return JXL_FAILURE("Invalid HybridUintConfig"); |
287 | 82 | } |
288 | 105k | nbits = CeilLog2Nonzero(split_exponent - msb_in_token + 1); |
289 | 105k | lsb_in_token = br->ReadBits(nbits); |
290 | 105k | } |
291 | 120k | if (lsb_in_token + msb_in_token > split_exponent) { |
292 | 34 | return JXL_FAILURE("Invalid HybridUintConfig"); |
293 | 34 | } |
294 | 120k | *uint_config = HybridUintConfig(split_exponent, msb_in_token, lsb_in_token); |
295 | 120k | return true; |
296 | 120k | } |
297 | | |
298 | | Status DecodeUintConfigs(size_t log_alpha_size, |
299 | | std::vector<HybridUintConfig>* uint_config, |
300 | 84.7k | BitReader* br) { |
301 | | // TODO(veluca): RLE? |
302 | 108k | for (auto& cfg : *uint_config) { |
303 | 108k | JXL_RETURN_IF_ERROR(DecodeUintConfig(log_alpha_size, &cfg, br)); |
304 | 108k | } |
305 | 84.7k | return true; |
306 | 84.7k | } |
307 | | |
308 | 152k | LZ77Params::LZ77Params() { Bundle::Init(this); } |
309 | 243k | Status LZ77Params::VisitFields(Visitor* JXL_RESTRICT visitor) { |
310 | 243k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &enabled)); |
311 | 243k | if (!visitor->Conditional(enabled)) return true; |
312 | 164k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(224), Val(512), Val(4096), |
313 | 164k | BitsOffset(15, 8), 224, &min_symbol)); |
314 | 164k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(3), Val(4), BitsOffset(2, 5), |
315 | 164k | BitsOffset(8, 9), 3, &min_length)); |
316 | 164k | return true; |
317 | 164k | } |
318 | | |
319 | 15.1M | void ANSCode::UpdateMaxNumBits(size_t ctx, size_t symbol) { |
320 | 15.1M | HybridUintConfig* cfg = &uint_config[ctx]; |
321 | | // LZ77 symbols use a different uint config. |
322 | 15.1M | if (lz77.enabled && lz77.nonserialized_distance_context != ctx && |
323 | 15.1M | symbol >= lz77.min_symbol) { |
324 | 69.5k | symbol -= lz77.min_symbol; |
325 | 69.5k | cfg = &lz77.length_uint_config; |
326 | 69.5k | } |
327 | 15.1M | size_t split_token = cfg->split_token; |
328 | 15.1M | size_t msb_in_token = cfg->msb_in_token; |
329 | 15.1M | size_t lsb_in_token = cfg->lsb_in_token; |
330 | 15.1M | size_t split_exponent = cfg->split_exponent; |
331 | 15.1M | if (symbol < split_token) { |
332 | 13.4M | max_num_bits = std::max(max_num_bits, split_exponent); |
333 | 13.4M | return; |
334 | 13.4M | } |
335 | 1.74M | uint32_t n_extra_bits = |
336 | 1.74M | split_exponent - (msb_in_token + lsb_in_token) + |
337 | 1.74M | ((symbol - split_token) >> (msb_in_token + lsb_in_token)); |
338 | 1.74M | size_t total_bits = msb_in_token + lsb_in_token + n_extra_bits + 1; |
339 | 1.74M | max_num_bits = std::max(max_num_bits, total_bits); |
340 | 1.74M | } |
341 | | |
342 | | Status DecodeHistograms(JxlMemoryManager* memory_manager, BitReader* br, |
343 | | size_t num_contexts, ANSCode* code, |
344 | 86.4k | std::vector<uint8_t>* context_map, bool disallow_lz77) { |
345 | 86.4k | JXL_RETURN_IF_ERROR(Bundle::Read(br, &code->lz77)); |
346 | 86.1k | if (code->lz77.enabled) { |
347 | 11.5k | num_contexts++; |
348 | 11.5k | JXL_RETURN_IF_ERROR(DecodeUintConfig(/*log_alpha_size=*/8, |
349 | 11.5k | &code->lz77.length_uint_config, br)); |
350 | 11.5k | } |
351 | 86.1k | if (code->lz77.enabled && disallow_lz77) { |
352 | 20 | return JXL_FAILURE("Using LZ77 when explicitly disallowed"); |
353 | 20 | } |
354 | 86.1k | size_t num_histograms = 1; |
355 | 86.1k | context_map->resize(num_contexts); |
356 | 86.1k | if (num_contexts > 1) { |
357 | 51.5k | JXL_RETURN_IF_ERROR( |
358 | 51.5k | DecodeContextMap(memory_manager, context_map, &num_histograms, br)); |
359 | 51.5k | } |
360 | 84.7k | JXL_DEBUG_V( |
361 | 84.7k | 4, "Decoded context map of size %" PRIuS " and %" PRIuS " histograms", |
362 | 84.7k | num_contexts, num_histograms); |
363 | 84.7k | code->lz77.nonserialized_distance_context = context_map->back(); |
364 | 84.7k | code->use_prefix_code = static_cast<bool>(br->ReadFixedBits<1>()); |
365 | 84.7k | if (code->use_prefix_code) { |
366 | 42.4k | code->log_alpha_size = PREFIX_MAX_BITS; |
367 | 42.4k | } else { |
368 | 42.3k | code->log_alpha_size = br->ReadFixedBits<2>() + 5; |
369 | 42.3k | } |
370 | 84.7k | code->uint_config.resize(num_histograms); |
371 | 84.7k | JXL_RETURN_IF_ERROR( |
372 | 84.7k | DecodeUintConfigs(code->log_alpha_size, &code->uint_config, br)); |
373 | 84.7k | const size_t max_alphabet_size = 1 << code->log_alpha_size; |
374 | 84.7k | JXL_RETURN_IF_ERROR(DecodeANSCodes(memory_manager, num_histograms, |
375 | 84.7k | max_alphabet_size, br, code)); |
376 | 83.7k | return true; |
377 | 84.7k | } |
378 | | |
379 | | StatusOr<ANSSymbolReader> ANSSymbolReader::Create(const ANSCode* code, |
380 | | BitReader* JXL_RESTRICT br, |
381 | 85.1k | size_t distance_multiplier) { |
382 | 85.1k | AlignedMemory lz77_window_storage; |
383 | 85.1k | if (code->lz77.enabled) { |
384 | 10.8k | JxlMemoryManager* memory_manager = code->memory_manager; |
385 | 10.8k | JXL_ASSIGN_OR_RETURN( |
386 | 10.8k | lz77_window_storage, |
387 | 10.8k | AlignedMemory::Create(memory_manager, kWindowSize * sizeof(uint32_t))); |
388 | 10.8k | } |
389 | 85.1k | return ANSSymbolReader(code, br, distance_multiplier, |
390 | 85.1k | std::move(lz77_window_storage)); |
391 | 85.1k | } |
392 | | |
393 | | ANSSymbolReader::ANSSymbolReader(const ANSCode* code, |
394 | | BitReader* JXL_RESTRICT br, |
395 | | size_t distance_multiplier, |
396 | | AlignedMemory&& lz77_window_storage) |
397 | 85.1k | : alias_tables_(code->alias_tables.address<AliasTable::Entry>()), |
398 | 85.1k | huffman_data_(code->huffman_data.data()), |
399 | 85.1k | use_prefix_code_(code->use_prefix_code), |
400 | 85.1k | configs(code->uint_config.data()), |
401 | 85.1k | lz77_window_storage_(std::move(lz77_window_storage)) { |
402 | 85.1k | if (!use_prefix_code_) { |
403 | 43.1k | state_ = static_cast<uint32_t>(br->ReadFixedBits<32>()); |
404 | 43.1k | log_alpha_size_ = code->log_alpha_size; |
405 | 43.1k | log_entry_size_ = ANS_LOG_TAB_SIZE - code->log_alpha_size; |
406 | 43.1k | entry_size_minus_1_ = (1 << log_entry_size_) - 1; |
407 | 43.1k | } else { |
408 | 41.9k | state_ = (ANS_SIGNATURE << 16u); |
409 | 41.9k | } |
410 | 85.1k | if (!code->lz77.enabled) return; |
411 | 10.8k | lz77_window_ = lz77_window_storage_.address<uint32_t>(); |
412 | 10.8k | lz77_ctx_ = code->lz77.nonserialized_distance_context; |
413 | 10.8k | lz77_length_uint_ = code->lz77.length_uint_config; |
414 | 10.8k | lz77_threshold_ = code->lz77.min_symbol; |
415 | 10.8k | lz77_min_length_ = code->lz77.min_length; |
416 | 10.8k | num_special_distances_ = distance_multiplier == 0 ? 0 : kNumSpecialDistances; |
417 | 694k | for (size_t i = 0; i < num_special_distances_; i++) { |
418 | 683k | special_distances_[i] = SpecialDistance(i, distance_multiplier); |
419 | 683k | } |
420 | 10.8k | } |
421 | | |
422 | | } // namespace jxl |