/src/libjxl/lib/jpegli/decode_marker.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/jpegli/decode_marker.h" |
7 | | |
8 | | #include <jxl/types.h> |
9 | | #include <string.h> |
10 | | |
11 | | #include "lib/jpegli/common.h" |
12 | | #include "lib/jpegli/decode_internal.h" |
13 | | #include "lib/jpegli/error.h" |
14 | | #include "lib/jpegli/huffman.h" |
15 | | #include "lib/jpegli/memory_manager.h" |
16 | | #include "lib/jxl/base/printf_macros.h" |
17 | | |
18 | | namespace jpegli { |
19 | | namespace { |
20 | | |
21 | | constexpr int kMaxDimPixels = 65535; |
22 | | constexpr uint8_t kIccProfileTag[12] = "ICC_PROFILE"; |
23 | | |
24 | | // Macros for commonly used error conditions. |
25 | | |
26 | | #define JPEG_VERIFY_LEN(n) \ |
27 | 60.2k | if (pos + (n) > len) { \ |
28 | 38 | JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \ |
29 | 38 | " need=%d len=%" PRIuS, \ |
30 | 38 | pos, static_cast<int>(n), len); \ |
31 | 38 | } |
32 | | |
33 | | #define JPEG_VERIFY_INPUT(var, low, high) \ |
34 | 368k | if ((var) < (low) || (var) > (high)) { \ |
35 | 500 | JPEGLI_ERROR("Invalid " #var ": %d", static_cast<int>(var)); \ |
36 | 500 | } |
37 | | |
38 | | #define JPEG_VERIFY_MARKER_END() \ |
39 | 15.8k | if (pos != len) { \ |
40 | 48 | JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS " actual=%" PRIuS, \ |
41 | 48 | len, pos); \ |
42 | 48 | } |
43 | | |
44 | 619k | inline int ReadUint8(const uint8_t* data, size_t* pos) { |
45 | 619k | return data[(*pos)++]; |
46 | 619k | } |
47 | | |
48 | 25.6k | inline int ReadUint16(const uint8_t* data, size_t* pos) { |
49 | 25.6k | int v = (data[*pos] << 8) + data[*pos + 1]; |
50 | 25.6k | *pos += 2; |
51 | 25.6k | return v; |
52 | 25.6k | } |
53 | | |
54 | 3.57k | void ProcessSOF(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
55 | 3.57k | jpeg_decomp_master* m = cinfo->master; |
56 | 3.57k | if (!m->found_soi_) { |
57 | 0 | JPEGLI_ERROR("Unexpected SOF marker."); |
58 | 0 | } |
59 | 3.57k | if (m->found_sof_) { |
60 | 6 | JPEGLI_ERROR("Duplicate SOF marker."); |
61 | 6 | } |
62 | 3.56k | m->found_sof_ = true; |
63 | 3.56k | cinfo->progressive_mode = TO_JXL_BOOL(cinfo->unread_marker == 0xc2); |
64 | 3.56k | cinfo->arith_code = 0; |
65 | 3.56k | size_t pos = 2; |
66 | 3.56k | JPEG_VERIFY_LEN(6); |
67 | 3.56k | cinfo->data_precision = ReadUint8(data, &pos); |
68 | 3.56k | cinfo->image_height = ReadUint16(data, &pos); |
69 | 3.56k | cinfo->image_width = ReadUint16(data, &pos); |
70 | 3.56k | cinfo->num_components = ReadUint8(data, &pos); |
71 | 3.56k | JPEG_VERIFY_INPUT(cinfo->data_precision, kJpegPrecision, kJpegPrecision); |
72 | 3.54k | JPEG_VERIFY_INPUT(cinfo->image_height, 1, kMaxDimPixels); |
73 | 3.53k | JPEG_VERIFY_INPUT(cinfo->image_width, 1, kMaxDimPixels); |
74 | 3.53k | JPEG_VERIFY_INPUT(cinfo->num_components, 1, kMaxComponents); |
75 | 3.50k | JPEG_VERIFY_LEN(3 * cinfo->num_components); |
76 | 3.50k | cinfo->comp_info = jpegli::Allocate<jpeg_component_info>( |
77 | 3.50k | cinfo, cinfo->num_components, JPOOL_IMAGE); |
78 | | |
79 | | // Read sampling factors and quant table index for each component. |
80 | 3.50k | uint8_t ids_seen[256] = {0}; |
81 | 3.50k | cinfo->max_h_samp_factor = 1; |
82 | 3.50k | cinfo->max_v_samp_factor = 1; |
83 | 10.0k | for (int i = 0; i < cinfo->num_components; ++i) { |
84 | 6.60k | jpeg_component_info* comp = &cinfo->comp_info[i]; |
85 | 6.60k | comp->component_index = i; |
86 | 6.60k | const int id = ReadUint8(data, &pos); |
87 | 6.60k | if (ids_seen[id]) { // (cf. section B.2.2, syntax of Ci) |
88 | 1 | JPEGLI_ERROR("Duplicate ID %d in SOF.", id); |
89 | 1 | } |
90 | 6.60k | ids_seen[id] = 1; |
91 | 6.60k | comp->component_id = id; |
92 | 6.60k | int factor = ReadUint8(data, &pos); |
93 | 6.60k | int h_samp_factor = factor >> 4; |
94 | 6.60k | int v_samp_factor = factor & 0xf; |
95 | 6.60k | JPEG_VERIFY_INPUT(h_samp_factor, 1, MAX_SAMP_FACTOR); |
96 | 6.57k | JPEG_VERIFY_INPUT(v_samp_factor, 1, MAX_SAMP_FACTOR); |
97 | 6.56k | comp->h_samp_factor = h_samp_factor; |
98 | 6.56k | comp->v_samp_factor = v_samp_factor; |
99 | 6.56k | cinfo->max_h_samp_factor = |
100 | 6.56k | std::max(cinfo->max_h_samp_factor, h_samp_factor); |
101 | 6.56k | cinfo->max_v_samp_factor = |
102 | 6.56k | std::max(cinfo->max_v_samp_factor, v_samp_factor); |
103 | 6.56k | int quant_tbl_idx = ReadUint8(data, &pos); |
104 | 6.56k | JPEG_VERIFY_INPUT(quant_tbl_idx, 0, NUM_QUANT_TBLS - 1); |
105 | 6.55k | comp->quant_tbl_no = quant_tbl_idx; |
106 | 6.55k | comp->quant_table = nullptr; // will be allocated after SOS marker |
107 | 6.55k | } |
108 | 3.45k | JPEG_VERIFY_MARKER_END(); |
109 | | |
110 | | // Set the input colorspace based on the markers we have seen and set |
111 | | // default output colorspace. |
112 | 3.43k | if (cinfo->num_components == 1) { |
113 | 1.79k | cinfo->jpeg_color_space = JCS_GRAYSCALE; |
114 | 1.79k | cinfo->out_color_space = JCS_GRAYSCALE; |
115 | 1.79k | } else if (cinfo->num_components == 3) { |
116 | 586 | if (cinfo->saw_JFIF_marker) { |
117 | 13 | cinfo->jpeg_color_space = JCS_YCbCr; |
118 | 573 | } else if (cinfo->saw_Adobe_marker) { |
119 | 11 | cinfo->jpeg_color_space = |
120 | 11 | cinfo->Adobe_transform == 0 ? JCS_RGB : JCS_YCbCr; |
121 | 562 | } else { |
122 | 562 | cinfo->jpeg_color_space = JCS_YCbCr; |
123 | 562 | if (cinfo->comp_info[0].component_id == 'R' && // |
124 | 562 | cinfo->comp_info[1].component_id == 'G' && // |
125 | 562 | cinfo->comp_info[2].component_id == 'B') { |
126 | 1 | cinfo->jpeg_color_space = JCS_RGB; |
127 | 1 | } |
128 | 562 | } |
129 | 586 | cinfo->out_color_space = JCS_RGB; |
130 | 1.05k | } else if (cinfo->num_components == 4) { |
131 | 430 | if (cinfo->saw_Adobe_marker) { |
132 | 67 | cinfo->jpeg_color_space = |
133 | 67 | cinfo->Adobe_transform == 0 ? JCS_CMYK : JCS_YCCK; |
134 | 363 | } else { |
135 | 363 | cinfo->jpeg_color_space = JCS_CMYK; |
136 | 363 | } |
137 | 430 | cinfo->out_color_space = JCS_CMYK; |
138 | 430 | } |
139 | | |
140 | | // We have checked above that none of the sampling factors are 0, so the max |
141 | | // sampling factors can not be 0. |
142 | 3.43k | cinfo->total_iMCU_rows = |
143 | 3.43k | DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE); |
144 | 3.43k | m->iMCU_cols_ = |
145 | 3.43k | DivCeil(cinfo->image_width, cinfo->max_h_samp_factor * DCTSIZE); |
146 | | // Compute the block dimensions for each component. |
147 | 9.91k | for (int i = 0; i < cinfo->num_components; ++i) { |
148 | 6.50k | jpeg_component_info* comp = &cinfo->comp_info[i]; |
149 | 6.50k | if (cinfo->max_h_samp_factor % comp->h_samp_factor != 0 || |
150 | 6.50k | cinfo->max_v_samp_factor % comp->v_samp_factor != 0) { |
151 | 28 | JPEGLI_ERROR("Non-integral subsampling ratios."); |
152 | 28 | } |
153 | 6.47k | m->h_factor[i] = cinfo->max_h_samp_factor / comp->h_samp_factor; |
154 | 6.47k | m->v_factor[i] = cinfo->max_v_samp_factor / comp->v_samp_factor; |
155 | 6.47k | comp->downsampled_width = DivCeil(cinfo->image_width, m->h_factor[i]); |
156 | 6.47k | comp->downsampled_height = DivCeil(cinfo->image_height, m->v_factor[i]); |
157 | 6.47k | comp->width_in_blocks = DivCeil(comp->downsampled_width, DCTSIZE); |
158 | 6.47k | comp->height_in_blocks = DivCeil(comp->downsampled_height, DCTSIZE); |
159 | 6.47k | } |
160 | 3.40k | memset(m->scan_progression_, 0, sizeof(m->scan_progression_)); |
161 | 3.40k | } |
162 | | |
163 | 6.86k | void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
164 | 6.86k | jpeg_decomp_master* m = cinfo->master; |
165 | 6.86k | if (!m->found_sof_) { |
166 | 1 | JPEGLI_ERROR("Unexpected SOS marker."); |
167 | 1 | } |
168 | 6.86k | m->found_sos_ = true; |
169 | 6.86k | size_t pos = 2; |
170 | 6.86k | JPEG_VERIFY_LEN(1); |
171 | 6.86k | cinfo->comps_in_scan = ReadUint8(data, &pos); |
172 | 6.86k | JPEG_VERIFY_INPUT(cinfo->comps_in_scan, 1, cinfo->num_components); |
173 | 6.83k | JPEG_VERIFY_INPUT(cinfo->comps_in_scan, 1, MAX_COMPS_IN_SCAN); |
174 | | |
175 | 6.83k | JPEG_VERIFY_LEN(2 * cinfo->comps_in_scan); |
176 | 6.83k | bool is_interleaved = (cinfo->comps_in_scan > 1); |
177 | 6.83k | uint8_t ids_seen[256] = {0}; |
178 | 6.83k | cinfo->blocks_in_MCU = 0; |
179 | 15.4k | for (int i = 0; i < cinfo->comps_in_scan; ++i) { |
180 | 8.74k | int id = ReadUint8(data, &pos); |
181 | 8.74k | if (ids_seen[id]) { // (cf. section B.2.3, regarding CSj) |
182 | 1 | JPEGLI_ERROR("Duplicate ID %d in SOS.", id); |
183 | 1 | } |
184 | 8.74k | ids_seen[id] = 1; |
185 | 8.74k | jpeg_component_info* comp = nullptr; |
186 | 30.5k | for (int j = 0; j < cinfo->num_components; ++j) { |
187 | 21.7k | if (cinfo->comp_info[j].component_id == id) { |
188 | 8.65k | comp = &cinfo->comp_info[j]; |
189 | 8.65k | cinfo->cur_comp_info[i] = comp; |
190 | 8.65k | } |
191 | 21.7k | } |
192 | 8.74k | if (!comp) { |
193 | 86 | JPEGLI_ERROR("SOS marker: Could not find component with id %d", id); |
194 | 86 | } |
195 | 8.65k | int c = ReadUint8(data, &pos); |
196 | 8.65k | comp->dc_tbl_no = c >> 4; |
197 | 8.65k | comp->ac_tbl_no = c & 0xf; |
198 | 8.65k | JPEG_VERIFY_INPUT(comp->dc_tbl_no, 0, 3); |
199 | 8.63k | JPEG_VERIFY_INPUT(comp->ac_tbl_no, 0, 3); |
200 | 8.63k | comp->MCU_width = is_interleaved ? comp->h_samp_factor : 1; |
201 | 8.63k | comp->MCU_height = is_interleaved ? comp->v_samp_factor : 1; |
202 | 8.63k | comp->MCU_blocks = comp->MCU_width * comp->MCU_height; |
203 | 8.63k | if (cinfo->blocks_in_MCU + comp->MCU_blocks > D_MAX_BLOCKS_IN_MCU) { |
204 | 2 | JPEGLI_ERROR("Too many blocks in MCU."); |
205 | 2 | } |
206 | 23.5k | for (int j = 0; j < comp->MCU_blocks; ++j) { |
207 | 14.9k | cinfo->MCU_membership[cinfo->blocks_in_MCU++] = i; |
208 | 14.9k | } |
209 | 8.62k | } |
210 | 6.72k | JPEG_VERIFY_LEN(3); |
211 | 6.71k | cinfo->Ss = ReadUint8(data, &pos); |
212 | 6.71k | cinfo->Se = ReadUint8(data, &pos); |
213 | 6.71k | JPEG_VERIFY_INPUT(cinfo->Ss, 0, 63); |
214 | 6.69k | JPEG_VERIFY_INPUT(cinfo->Se, cinfo->Ss, 63); |
215 | 6.67k | int c = ReadUint8(data, &pos); |
216 | 6.67k | cinfo->Ah = c >> 4; |
217 | 6.67k | cinfo->Al = c & 0xf; |
218 | 6.67k | JPEG_VERIFY_MARKER_END(); |
219 | | |
220 | 6.66k | if (cinfo->input_scan_number == 0) { |
221 | 3.21k | m->is_multiscan_ = (cinfo->comps_in_scan < cinfo->num_components || |
222 | 3.21k | FROM_JXL_BOOL(cinfo->progressive_mode)); |
223 | 3.21k | } |
224 | 6.66k | if (cinfo->Ah != 0 && cinfo->Al != cinfo->Ah - 1) { |
225 | | // section G.1.1.1.2 : Successive approximation control only improves |
226 | | // by one bit at a time. |
227 | 14 | JPEGLI_ERROR("Invalid progressive parameters: Al=%d Ah=%d", cinfo->Al, |
228 | 14 | cinfo->Ah); |
229 | 14 | } |
230 | 6.64k | if (!cinfo->progressive_mode) { |
231 | 780 | cinfo->Ss = 0; |
232 | 780 | cinfo->Se = 63; |
233 | 780 | cinfo->Ah = 0; |
234 | 780 | cinfo->Al = 0; |
235 | 780 | } |
236 | 6.64k | const uint16_t scan_bitmask = |
237 | 6.64k | cinfo->Ah == 0 ? (0xffff << cinfo->Al) : (1u << cinfo->Al); |
238 | 6.64k | const uint16_t refinement_bitmask = (1 << cinfo->Al) - 1; |
239 | 6.64k | if (!cinfo->coef_bits) { |
240 | 3.20k | cinfo->coef_bits = |
241 | 3.20k | Allocate<int[DCTSIZE2]>(cinfo, cinfo->num_components * 2, JPOOL_IMAGE); |
242 | 3.20k | m->coef_bits_latch = |
243 | 3.20k | Allocate<int[SAVED_COEFS]>(cinfo, cinfo->num_components, JPOOL_IMAGE); |
244 | 3.20k | m->prev_coef_bits_latch = |
245 | 3.20k | Allocate<int[SAVED_COEFS]>(cinfo, cinfo->num_components, JPOOL_IMAGE); |
246 | | |
247 | 9.29k | for (int c = 0; c < cinfo->num_components; ++c) { |
248 | 395k | for (int i = 0; i < DCTSIZE2; ++i) { |
249 | 389k | cinfo->coef_bits[c][i] = -1; |
250 | 389k | if (i < SAVED_COEFS) { |
251 | 60.9k | m->coef_bits_latch[c][i] = -1; |
252 | 60.9k | } |
253 | 389k | } |
254 | 6.09k | } |
255 | 3.20k | } |
256 | | |
257 | 15.1k | for (int i = 0; i < cinfo->comps_in_scan; ++i) { |
258 | 8.49k | int comp_idx = cinfo->cur_comp_info[i]->component_index; |
259 | 196k | for (int k = cinfo->Ss; k <= cinfo->Se; ++k) { |
260 | 187k | if (m->scan_progression_[comp_idx][k] & scan_bitmask) { |
261 | 23 | JPEGLI_ERROR( |
262 | 23 | "Overlapping scans: component=%d k=%d prev_mask: %u cur_mask %u", |
263 | 23 | comp_idx, k, m->scan_progression_[i][k], scan_bitmask); |
264 | 23 | } |
265 | 187k | if (m->scan_progression_[comp_idx][k] & refinement_bitmask) { |
266 | 2 | JPEGLI_ERROR( |
267 | 2 | "Invalid scan order, a more refined scan was already done: " |
268 | 2 | "component=%d k=%d prev_mask=%u cur_mask=%u", |
269 | 2 | comp_idx, k, m->scan_progression_[i][k], scan_bitmask); |
270 | 2 | } |
271 | 187k | m->scan_progression_[comp_idx][k] |= scan_bitmask; |
272 | 187k | } |
273 | 8.49k | } |
274 | 6.62k | if (cinfo->Al > 10) { |
275 | 1 | JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al); |
276 | 1 | } |
277 | 6.62k | } |
278 | | |
279 | | // Reads the Define Huffman Table (DHT) marker segment and builds the Huffman |
280 | | // decoding table in either dc_huff_lut_ or ac_huff_lut_, depending on the type |
281 | | // and solt_id of Huffman code being read. |
282 | 2.44k | void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
283 | 2.44k | size_t pos = 2; |
284 | 2.44k | if (pos == len) { |
285 | 1 | JPEGLI_ERROR("DHT marker: no Huffman table found"); |
286 | 1 | } |
287 | 14.5k | while (pos < len) { |
288 | 12.2k | JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength); |
289 | | // The index of the Huffman code in the current set of Huffman codes. For AC |
290 | | // component Huffman codes, 0x10 is added to the index. |
291 | 12.2k | int slot_id = ReadUint8(data, &pos); |
292 | 12.2k | int huffman_index = slot_id; |
293 | 12.2k | bool is_ac_table = ((slot_id & 0x10) != 0); |
294 | 12.2k | JHUFF_TBL** table; |
295 | 12.2k | if (is_ac_table) { |
296 | 3.23k | huffman_index -= 0x10; |
297 | 3.23k | JPEG_VERIFY_INPUT(huffman_index, 0, NUM_HUFF_TBLS - 1); |
298 | 3.13k | table = &cinfo->ac_huff_tbl_ptrs[huffman_index]; |
299 | 9.03k | } else { |
300 | 9.03k | JPEG_VERIFY_INPUT(huffman_index, 0, NUM_HUFF_TBLS - 1); |
301 | 9.02k | table = &cinfo->dc_huff_tbl_ptrs[huffman_index]; |
302 | 9.02k | } |
303 | 12.1k | if (*table == nullptr) { |
304 | 1.27k | *table = jpegli_alloc_huff_table(reinterpret_cast<j_common_ptr>(cinfo)); |
305 | 1.27k | } |
306 | 12.1k | int total_count = 0; |
307 | 206k | for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) { |
308 | 194k | int count = ReadUint8(data, &pos); |
309 | 194k | (*table)->bits[i] = count; |
310 | 194k | total_count += count; |
311 | 194k | } |
312 | 12.1k | if (is_ac_table) { |
313 | 3.13k | JPEG_VERIFY_INPUT(total_count, 0, kJpegHuffmanAlphabetSize); |
314 | 9.02k | } else { |
315 | | // Allow symbols up to 15 here, we check later whether any invalid symbols |
316 | | // are actually decoded. |
317 | | // TODO(szabadka) Make sure decoder works (does not crash) with up to |
318 | | // 15-nbits DC symbols and then increase kJpegDCAlphabetSize. |
319 | 9.02k | JPEG_VERIFY_INPUT(total_count, 0, 16); |
320 | 8.99k | } |
321 | 12.1k | JPEG_VERIFY_LEN(total_count); |
322 | 112k | for (int i = 0; i < total_count; ++i) { |
323 | 100k | int value = ReadUint8(data, &pos); |
324 | 100k | if (!is_ac_table) { |
325 | 3.10k | JPEG_VERIFY_INPUT(value, 0, 15); |
326 | 3.08k | } |
327 | 100k | (*table)->huffval[i] = value; |
328 | 100k | } |
329 | 3.00M | for (int i = total_count; i < kJpegHuffmanAlphabetSize; ++i) { |
330 | 2.99M | (*table)->huffval[i] = 0; |
331 | 2.99M | } |
332 | 12.0k | } |
333 | 2.25k | JPEG_VERIFY_MARKER_END(); |
334 | 2.25k | } |
335 | | |
336 | 3.34k | void ProcessDQT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
337 | 3.34k | jpeg_decomp_master* m = cinfo->master; |
338 | 3.34k | if (m->found_sos_) { |
339 | 8 | JPEGLI_ERROR("Updating quant tables between scans is not supported."); |
340 | 8 | } |
341 | 3.33k | size_t pos = 2; |
342 | 3.33k | if (pos == len) { |
343 | 1 | JPEGLI_ERROR("DQT marker: no quantization table found"); |
344 | 1 | } |
345 | 7.31k | while (pos < len) { |
346 | 4.10k | JPEG_VERIFY_LEN(1); |
347 | 4.10k | int quant_table_index = ReadUint8(data, &pos); |
348 | 4.10k | int precision = quant_table_index >> 4; |
349 | 4.10k | JPEG_VERIFY_INPUT(precision, 0, 1); |
350 | 4.01k | quant_table_index &= 0xf; |
351 | 4.01k | JPEG_VERIFY_INPUT(quant_table_index, 0, NUM_QUANT_TBLS - 1); |
352 | 4.00k | JPEG_VERIFY_LEN((precision + 1) * DCTSIZE2); |
353 | | |
354 | 4.00k | if (cinfo->quant_tbl_ptrs[quant_table_index] == nullptr) { |
355 | 3.21k | cinfo->quant_tbl_ptrs[quant_table_index] = |
356 | 3.21k | jpegli_alloc_quant_table(reinterpret_cast<j_common_ptr>(cinfo)); |
357 | 3.21k | } |
358 | 4.00k | JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[quant_table_index]; |
359 | | |
360 | 258k | for (size_t i = 0; i < DCTSIZE2; ++i) { |
361 | 254k | int quant_val = |
362 | 254k | precision ? ReadUint16(data, &pos) : ReadUint8(data, &pos); |
363 | 254k | JPEG_VERIFY_INPUT(quant_val, 1, 65535); |
364 | 254k | quant_table->quantval[kJPEGNaturalOrder[i]] = quant_val; |
365 | 254k | } |
366 | 4.00k | } |
367 | 3.20k | JPEG_VERIFY_MARKER_END(); |
368 | 3.20k | } |
369 | | |
370 | 5 | void ProcessDNL(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
371 | | // Ignore marker. |
372 | 5 | } |
373 | | |
374 | 294 | void ProcessDRI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
375 | 294 | jpeg_decomp_master* m = cinfo->master; |
376 | 294 | if (m->found_dri_) { |
377 | 1 | JPEGLI_ERROR("Duplicate DRI marker."); |
378 | 1 | } |
379 | 293 | m->found_dri_ = true; |
380 | 293 | size_t pos = 2; |
381 | 293 | JPEG_VERIFY_LEN(2); |
382 | 291 | cinfo->restart_interval = ReadUint16(data, &pos); |
383 | 291 | JPEG_VERIFY_MARKER_END(); |
384 | 275 | } |
385 | | |
386 | 11.3k | void ProcessAPP(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
387 | 11.3k | jpeg_decomp_master* m = cinfo->master; |
388 | 11.3k | const uint8_t marker = cinfo->unread_marker; |
389 | 11.3k | const uint8_t* payload = data + 2; |
390 | 11.3k | size_t payload_size = len - 2; |
391 | 11.3k | if (marker == 0xE0) { |
392 | 740 | if (payload_size >= 14 && memcmp(payload, "JFIF", 4) == 0) { |
393 | 259 | cinfo->saw_JFIF_marker = TRUE; |
394 | 259 | cinfo->JFIF_major_version = payload[5]; |
395 | 259 | cinfo->JFIF_minor_version = payload[6]; |
396 | 259 | cinfo->density_unit = payload[7]; |
397 | 259 | cinfo->X_density = (payload[8] << 8) + payload[9]; |
398 | 259 | cinfo->Y_density = (payload[10] << 8) + payload[11]; |
399 | 259 | } |
400 | 10.5k | } else if (marker == 0xEE) { |
401 | 8.83k | if (payload_size >= 12 && memcmp(payload, "Adobe", 5) == 0) { |
402 | 287 | cinfo->saw_Adobe_marker = TRUE; |
403 | 287 | cinfo->Adobe_transform = payload[11]; |
404 | 287 | } |
405 | 8.83k | } else if (marker == 0xE2) { |
406 | 1.17k | if (payload_size >= sizeof(kIccProfileTag) && |
407 | 1.17k | memcmp(payload, kIccProfileTag, sizeof(kIccProfileTag)) == 0) { |
408 | 98 | payload += sizeof(kIccProfileTag); |
409 | 98 | payload_size -= sizeof(kIccProfileTag); |
410 | 98 | if (payload_size < 2) { |
411 | 1 | JPEGLI_ERROR("ICC chunk is too small."); |
412 | 1 | } |
413 | 97 | uint8_t index = payload[0]; |
414 | 97 | uint8_t total = payload[1]; |
415 | 97 | ++m->icc_index_; |
416 | 97 | if (m->icc_index_ != index) { |
417 | 10 | JPEGLI_ERROR("Invalid ICC chunk order."); |
418 | 10 | } |
419 | 87 | if (total == 0) { |
420 | 1 | JPEGLI_ERROR("Invalid ICC chunk total."); |
421 | 1 | } |
422 | 86 | if (m->icc_total_ == 0) { |
423 | 54 | m->icc_total_ = total; |
424 | 54 | } else if (m->icc_total_ != total) { |
425 | 14 | JPEGLI_ERROR("Invalid ICC chunk total."); |
426 | 14 | } |
427 | 72 | if (m->icc_index_ > m->icc_total_) { |
428 | 1 | JPEGLI_ERROR("Invalid ICC chunk index."); |
429 | 1 | } |
430 | 71 | m->icc_profile_.insert(m->icc_profile_.end(), payload + 2, |
431 | 71 | payload + payload_size); |
432 | 71 | } |
433 | 1.17k | } |
434 | 11.3k | } |
435 | | |
436 | 520 | void ProcessCOM(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
437 | | // Ignore marker. |
438 | 520 | } |
439 | | |
440 | 4.37k | void ProcessSOI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
441 | 4.37k | jpeg_decomp_master* m = cinfo->master; |
442 | 4.37k | if (m->found_soi_) { |
443 | 37 | JPEGLI_ERROR("Duplicate SOI marker"); |
444 | 37 | } |
445 | 4.33k | m->found_soi_ = true; |
446 | 4.33k | } |
447 | | |
448 | 2.94k | void ProcessEOI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
449 | 2.94k | cinfo->master->found_eoi_ = true; |
450 | 2.94k | } |
451 | | |
452 | 0 | void SaveMarker(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { |
453 | 0 | const uint8_t marker = cinfo->unread_marker; |
454 | 0 | const uint8_t* payload = data + 2; |
455 | 0 | size_t payload_size = len - 2; |
456 | | |
457 | | // Insert new saved marker to the head of the list. |
458 | 0 | jpeg_saved_marker_ptr next = cinfo->marker_list; |
459 | 0 | cinfo->marker_list = |
460 | 0 | jpegli::Allocate<jpeg_marker_struct>(cinfo, 1, JPOOL_IMAGE); |
461 | 0 | cinfo->marker_list->next = next; |
462 | 0 | cinfo->marker_list->marker = marker; |
463 | 0 | cinfo->marker_list->original_length = payload_size; |
464 | 0 | cinfo->marker_list->data_length = payload_size; |
465 | 0 | cinfo->marker_list->data = |
466 | 0 | jpegli::Allocate<uint8_t>(cinfo, payload_size, JPOOL_IMAGE); |
467 | 0 | memcpy(cinfo->marker_list->data, payload, payload_size); |
468 | 0 | } |
469 | | |
470 | | uint8_t ProcessNextMarker(j_decompress_ptr cinfo, const uint8_t* const data, |
471 | 17.1M | const size_t len, size_t* pos) { |
472 | 17.1M | jpeg_decomp_master* m = cinfo->master; |
473 | 17.1M | size_t num_skipped = 0; |
474 | 17.1M | uint8_t marker = cinfo->unread_marker; |
475 | 17.1M | if (marker == 0) { |
476 | | // kIsValidMarker[i] == 1 means (0xc0 + i) is a valid marker. |
477 | 305k | static const uint8_t kIsValidMarker[] = { |
478 | 305k | 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, |
479 | 305k | 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
480 | 305k | 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, |
481 | 305k | }; |
482 | | // Skip bytes between markers. |
483 | 20.8M | while (*pos + 1 < len && (data[*pos] != 0xff || data[*pos + 1] < 0xc0 || |
484 | 20.5M | !kIsValidMarker[data[*pos + 1] - 0xc0])) { |
485 | 20.5M | ++(*pos); |
486 | 20.5M | ++num_skipped; |
487 | 20.5M | } |
488 | 305k | if (*pos + 2 > len) { |
489 | 270k | return kNeedMoreInput; |
490 | 270k | } |
491 | 35.6k | marker = data[*pos + 1]; |
492 | 35.6k | if (num_skipped > 0) { |
493 | 7.58k | if (m->found_soi_) { |
494 | 7.49k | JPEGLI_WARN("Skipped %d bytes before marker 0x%02x", |
495 | 7.49k | static_cast<int>(num_skipped), marker); |
496 | 7.49k | } else { |
497 | 83 | JPEGLI_ERROR("Did not find SOI marker."); |
498 | 83 | } |
499 | 7.58k | } |
500 | 35.5k | *pos += 2; |
501 | 35.5k | cinfo->unread_marker = marker; |
502 | 35.5k | } |
503 | 16.9M | if (!m->found_soi_ && marker != 0xd8) { |
504 | 13 | JPEGLI_ERROR("Did not find SOI marker."); |
505 | 13 | } |
506 | 16.9M | if (GetMarkerProcessor(cinfo)) { |
507 | 0 | return kHandleMarkerProcessor; |
508 | 0 | } |
509 | 16.9M | const uint8_t* marker_data = &data[*pos]; |
510 | 16.9M | size_t marker_len = 0; |
511 | 16.9M | if (marker != 0xd8 && marker != 0xd9) { |
512 | 16.9M | if (*pos + 2 > len) { |
513 | 8.54k | return kNeedMoreInput; |
514 | 8.54k | } |
515 | 16.8M | marker_len += (data[*pos] << 8) + data[*pos + 1]; |
516 | 16.8M | if (marker_len < 2) { |
517 | 5 | JPEGLI_ERROR("Invalid marker length"); |
518 | 5 | } |
519 | 16.8M | if (*pos + marker_len > len) { |
520 | | // TODO(szabadka) Limit our memory usage by using the skip_input_data |
521 | | // source manager callback on APP markers that are not saved. |
522 | 16.8M | return kNeedMoreInput; |
523 | 16.8M | } |
524 | 28.4k | if (marker >= 0xe0 && m->markers_to_save_[marker - 0xe0]) { |
525 | 0 | SaveMarker(cinfo, marker_data, marker_len); |
526 | 0 | } |
527 | 28.4k | } |
528 | 35.7k | if (marker == 0xc0 || marker == 0xc1 || marker == 0xc2) { |
529 | 3.57k | ProcessSOF(cinfo, marker_data, marker_len); |
530 | 32.1k | } else if (marker == 0xc4) { |
531 | 2.44k | ProcessDHT(cinfo, marker_data, marker_len); |
532 | 29.7k | } else if (marker == 0xda) { |
533 | 6.86k | ProcessSOS(cinfo, marker_data, marker_len); |
534 | 22.8k | } else if (marker == 0xdb) { |
535 | 3.34k | ProcessDQT(cinfo, marker_data, marker_len); |
536 | 19.5k | } else if (marker == 0xdc) { |
537 | 5 | ProcessDNL(cinfo, marker_data, marker_len); |
538 | 19.5k | } else if (marker == 0xdd) { |
539 | 294 | ProcessDRI(cinfo, marker_data, marker_len); |
540 | 19.2k | } else if (marker >= 0xe0 && marker <= 0xef) { |
541 | 11.3k | ProcessAPP(cinfo, marker_data, marker_len); |
542 | 11.3k | } else if (marker == 0xfe) { |
543 | 520 | ProcessCOM(cinfo, marker_data, marker_len); |
544 | 7.40k | } else if (marker == 0xd8) { |
545 | 4.37k | ProcessSOI(cinfo, marker_data, marker_len); |
546 | 4.37k | } else if (marker == 0xd9) { |
547 | 2.94k | ProcessEOI(cinfo, marker_data, marker_len); |
548 | 2.94k | } else { |
549 | 88 | JPEGLI_ERROR("Unexpected marker 0x%x", marker); |
550 | 88 | } |
551 | 35.6k | *pos += marker_len; |
552 | 35.6k | cinfo->unread_marker = 0; |
553 | 35.6k | if (marker == 0xda) { |
554 | 6.62k | return JPEG_REACHED_SOS; |
555 | 29.0k | } else if (marker == 0xd9) { |
556 | 2.94k | return JPEG_REACHED_EOI; |
557 | 2.94k | } |
558 | 26.1k | return kProcessNextMarker; |
559 | 35.6k | } |
560 | | |
561 | | } // namespace |
562 | | |
563 | 16.9M | jpeg_marker_parser_method GetMarkerProcessor(j_decompress_ptr cinfo) { |
564 | 16.9M | jpeg_decomp_master* m = cinfo->master; |
565 | 16.9M | uint8_t marker = cinfo->unread_marker; |
566 | 16.9M | jpeg_marker_parser_method callback = nullptr; |
567 | 16.9M | if (marker >= 0xe0 && marker <= 0xef) { |
568 | 5.61M | callback = m->app_marker_parsers[marker - 0xe0]; |
569 | 11.2M | } else if (marker == 0xfe) { |
570 | 1.09M | callback = m->com_marker_parser; |
571 | 1.09M | } |
572 | 16.9M | return callback; |
573 | 16.9M | } |
574 | | |
575 | | int ProcessMarkers(j_decompress_ptr cinfo, const uint8_t* const data, |
576 | 17.1M | const size_t len, size_t* pos) { |
577 | 17.1M | for (;;) { |
578 | 17.1M | int status = ProcessNextMarker(cinfo, data, len, pos); |
579 | 17.1M | if (status != kProcessNextMarker) { |
580 | 17.1M | return status; |
581 | 17.1M | } |
582 | 17.1M | } |
583 | 17.1M | } |
584 | | |
585 | | } // namespace jpegli |