From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- third_party/jpeg-xl/lib/jpegli/decode_marker.cc | 588 ++++++++++++++++++++++++ 1 file changed, 588 insertions(+) create mode 100644 third_party/jpeg-xl/lib/jpegli/decode_marker.cc (limited to 'third_party/jpeg-xl/lib/jpegli/decode_marker.cc') diff --git a/third_party/jpeg-xl/lib/jpegli/decode_marker.cc b/third_party/jpeg-xl/lib/jpegli/decode_marker.cc new file mode 100644 index 0000000000..c5c5790cdf --- /dev/null +++ b/third_party/jpeg-xl/lib/jpegli/decode_marker.cc @@ -0,0 +1,588 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "lib/jpegli/decode_marker.h" + +#include + +#include "lib/jpegli/common.h" +#include "lib/jpegli/decode_internal.h" +#include "lib/jpegli/error.h" +#include "lib/jpegli/huffman.h" +#include "lib/jpegli/memory_manager.h" +#include "lib/jxl/base/printf_macros.h" + +namespace jpegli { +namespace { + +constexpr int kMaxDimPixels = 65535; +constexpr uint8_t kIccProfileTag[12] = "ICC_PROFILE"; + +// Macros for commonly used error conditions. + +#define JPEG_VERIFY_LEN(n) \ + if (pos + (n) > len) { \ + return JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \ + " need=%d len=%" PRIuS, \ + pos, static_cast(n), len); \ + } + +#define JPEG_VERIFY_INPUT(var, low, high) \ + if ((var) < (low) || (var) > (high)) { \ + return JPEGLI_ERROR("Invalid " #var ": %d", static_cast(var)); \ + } + +#define JPEG_VERIFY_MARKER_END() \ + if (pos != len) { \ + return JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS \ + " actual=%" PRIuS, \ + len, pos); \ + } + +inline int ReadUint8(const uint8_t* data, size_t* pos) { + return data[(*pos)++]; +} + +inline int ReadUint16(const uint8_t* data, size_t* pos) { + int v = (data[*pos] << 8) + data[*pos + 1]; + *pos += 2; + return v; +} + +void ProcessSOF(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + jpeg_decomp_master* m = cinfo->master; + if (!m->found_soi_) { + JPEGLI_ERROR("Unexpected SOF marker."); + } + if (m->found_sof_) { + JPEGLI_ERROR("Duplicate SOF marker."); + } + m->found_sof_ = true; + cinfo->progressive_mode = (cinfo->unread_marker == 0xc2); + cinfo->arith_code = 0; + size_t pos = 2; + JPEG_VERIFY_LEN(6); + cinfo->data_precision = ReadUint8(data, &pos); + cinfo->image_height = ReadUint16(data, &pos); + cinfo->image_width = ReadUint16(data, &pos); + cinfo->num_components = ReadUint8(data, &pos); + JPEG_VERIFY_INPUT(cinfo->data_precision, kJpegPrecision, kJpegPrecision); + JPEG_VERIFY_INPUT(cinfo->image_height, 1, kMaxDimPixels); + JPEG_VERIFY_INPUT(cinfo->image_width, 1, kMaxDimPixels); + JPEG_VERIFY_INPUT(cinfo->num_components, 1, kMaxComponents); + JPEG_VERIFY_LEN(3 * cinfo->num_components); + cinfo->comp_info = jpegli::Allocate( + cinfo, cinfo->num_components, JPOOL_IMAGE); + + // Read sampling factors and quant table index for each component. + uint8_t ids_seen[256] = {0}; + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (int i = 0; i < cinfo->num_components; ++i) { + jpeg_component_info* comp = &cinfo->comp_info[i]; + comp->component_index = i; + const int id = ReadUint8(data, &pos); + if (ids_seen[id]) { // (cf. section B.2.2, syntax of Ci) + JPEGLI_ERROR("Duplicate ID %d in SOF.", id); + } + ids_seen[id] = 1; + comp->component_id = id; + int factor = ReadUint8(data, &pos); + int h_samp_factor = factor >> 4; + int v_samp_factor = factor & 0xf; + JPEG_VERIFY_INPUT(h_samp_factor, 1, MAX_SAMP_FACTOR); + JPEG_VERIFY_INPUT(v_samp_factor, 1, MAX_SAMP_FACTOR); + comp->h_samp_factor = h_samp_factor; + comp->v_samp_factor = v_samp_factor; + cinfo->max_h_samp_factor = + std::max(cinfo->max_h_samp_factor, h_samp_factor); + cinfo->max_v_samp_factor = + std::max(cinfo->max_v_samp_factor, v_samp_factor); + int quant_tbl_idx = ReadUint8(data, &pos); + JPEG_VERIFY_INPUT(quant_tbl_idx, 0, NUM_QUANT_TBLS - 1); + comp->quant_tbl_no = quant_tbl_idx; + if (cinfo->quant_tbl_ptrs[quant_tbl_idx] == nullptr) { + JPEGLI_ERROR("Quantization table with index %u not found", quant_tbl_idx); + } + comp->quant_table = nullptr; // will be allocated after SOS marker + } + JPEG_VERIFY_MARKER_END(); + + // Set the input colorspace based on the markers we have seen and set + // default output colorspace. + if (cinfo->num_components == 1) { + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + } else if (cinfo->num_components == 3) { + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; + } else if (cinfo->saw_Adobe_marker) { + cinfo->jpeg_color_space = + cinfo->Adobe_transform == 0 ? JCS_RGB : JCS_YCbCr; + } else { + cinfo->jpeg_color_space = JCS_YCbCr; + if (cinfo->comp_info[0].component_id == 'R' && // + cinfo->comp_info[1].component_id == 'G' && // + cinfo->comp_info[2].component_id == 'B') { + cinfo->jpeg_color_space = JCS_RGB; + } + } + cinfo->out_color_space = JCS_RGB; + } else if (cinfo->num_components == 4) { + if (cinfo->saw_Adobe_marker) { + cinfo->jpeg_color_space = + cinfo->Adobe_transform == 0 ? JCS_CMYK : JCS_YCCK; + } else { + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + } + + // We have checked above that none of the sampling factors are 0, so the max + // sampling factors can not be 0. + cinfo->total_iMCU_rows = + DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE); + m->iMCU_cols_ = + DivCeil(cinfo->image_width, cinfo->max_h_samp_factor * DCTSIZE); + // Compute the block dimensions for each component. + for (int i = 0; i < cinfo->num_components; ++i) { + jpeg_component_info* comp = &cinfo->comp_info[i]; + if (cinfo->max_h_samp_factor % comp->h_samp_factor != 0 || + cinfo->max_v_samp_factor % comp->v_samp_factor != 0) { + JPEGLI_ERROR("Non-integral subsampling ratios."); + } + m->h_factor[i] = cinfo->max_h_samp_factor / comp->h_samp_factor; + m->v_factor[i] = cinfo->max_v_samp_factor / comp->v_samp_factor; + comp->downsampled_width = DivCeil(cinfo->image_width, m->h_factor[i]); + comp->downsampled_height = DivCeil(cinfo->image_height, m->v_factor[i]); + comp->width_in_blocks = DivCeil(comp->downsampled_width, DCTSIZE); + comp->height_in_blocks = DivCeil(comp->downsampled_height, DCTSIZE); + } + memset(m->scan_progression_, 0, sizeof(m->scan_progression_)); +} + +void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + jpeg_decomp_master* m = cinfo->master; + if (!m->found_sof_) { + JPEGLI_ERROR("Unexpected SOS marker."); + } + size_t pos = 2; + JPEG_VERIFY_LEN(1); + cinfo->comps_in_scan = ReadUint8(data, &pos); + JPEG_VERIFY_INPUT(cinfo->comps_in_scan, 1, cinfo->num_components); + JPEG_VERIFY_INPUT(cinfo->comps_in_scan, 1, MAX_COMPS_IN_SCAN); + + JPEG_VERIFY_LEN(2 * cinfo->comps_in_scan); + bool is_interleaved = (cinfo->comps_in_scan > 1); + uint8_t ids_seen[256] = {0}; + cinfo->blocks_in_MCU = 0; + for (int i = 0; i < cinfo->comps_in_scan; ++i) { + int id = ReadUint8(data, &pos); + if (ids_seen[id]) { // (cf. section B.2.3, regarding CSj) + return JPEGLI_ERROR("Duplicate ID %d in SOS.", id); + } + ids_seen[id] = 1; + jpeg_component_info* comp = nullptr; + for (int j = 0; j < cinfo->num_components; ++j) { + if (cinfo->comp_info[j].component_id == id) { + comp = &cinfo->comp_info[j]; + cinfo->cur_comp_info[i] = comp; + } + } + if (!comp) { + return JPEGLI_ERROR("SOS marker: Could not find component with id %d", + id); + } + int c = ReadUint8(data, &pos); + comp->dc_tbl_no = c >> 4; + comp->ac_tbl_no = c & 0xf; + JPEG_VERIFY_INPUT(comp->dc_tbl_no, 0, 3); + JPEG_VERIFY_INPUT(comp->ac_tbl_no, 0, 3); + comp->MCU_width = is_interleaved ? comp->h_samp_factor : 1; + comp->MCU_height = is_interleaved ? comp->v_samp_factor : 1; + comp->MCU_blocks = comp->MCU_width * comp->MCU_height; + if (cinfo->blocks_in_MCU + comp->MCU_blocks > D_MAX_BLOCKS_IN_MCU) { + JPEGLI_ERROR("Too many blocks in MCU."); + } + for (int j = 0; j < comp->MCU_blocks; ++j) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = i; + } + } + JPEG_VERIFY_LEN(3); + cinfo->Ss = ReadUint8(data, &pos); + cinfo->Se = ReadUint8(data, &pos); + JPEG_VERIFY_INPUT(cinfo->Ss, 0, 63); + JPEG_VERIFY_INPUT(cinfo->Se, cinfo->Ss, 63); + int c = ReadUint8(data, &pos); + cinfo->Ah = c >> 4; + cinfo->Al = c & 0xf; + JPEG_VERIFY_MARKER_END(); + + if (cinfo->input_scan_number == 0) { + m->is_multiscan_ = (cinfo->comps_in_scan < cinfo->num_components || + cinfo->progressive_mode); + } + if (cinfo->Ah != 0 && cinfo->Al != cinfo->Ah - 1) { + // section G.1.1.1.2 : Successive approximation control only improves + // by one bit at a time. + JPEGLI_ERROR("Invalid progressive parameters: Al=%d Ah=%d", cinfo->Al, + cinfo->Ah); + } + if (!cinfo->progressive_mode) { + cinfo->Ss = 0; + cinfo->Se = 63; + cinfo->Ah = 0; + cinfo->Al = 0; + } + const uint16_t scan_bitmask = + cinfo->Ah == 0 ? (0xffff << cinfo->Al) : (1u << cinfo->Al); + const uint16_t refinement_bitmask = (1 << cinfo->Al) - 1; + if (!cinfo->coef_bits) { + cinfo->coef_bits = + Allocate(cinfo, cinfo->num_components * 2, JPOOL_IMAGE); + m->coef_bits_latch = + Allocate(cinfo, cinfo->num_components, JPOOL_IMAGE); + m->prev_coef_bits_latch = + Allocate(cinfo, cinfo->num_components, JPOOL_IMAGE); + + for (int c = 0; c < cinfo->num_components; ++c) { + for (int i = 0; i < DCTSIZE2; ++i) { + cinfo->coef_bits[c][i] = -1; + if (i < SAVED_COEFS) { + m->coef_bits_latch[c][i] = -1; + } + } + } + } + + for (int i = 0; i < cinfo->comps_in_scan; ++i) { + int comp_idx = cinfo->cur_comp_info[i]->component_index; + for (int k = cinfo->Ss; k <= cinfo->Se; ++k) { + if (m->scan_progression_[comp_idx][k] & scan_bitmask) { + return JPEGLI_ERROR( + "Overlapping scans: component=%d k=%d prev_mask: %u cur_mask %u", + comp_idx, k, m->scan_progression_[i][k], scan_bitmask); + } + if (m->scan_progression_[comp_idx][k] & refinement_bitmask) { + return JPEGLI_ERROR( + "Invalid scan order, a more refined scan was already done: " + "component=%d k=%d prev_mask=%u cur_mask=%u", + comp_idx, k, m->scan_progression_[i][k], scan_bitmask); + } + m->scan_progression_[comp_idx][k] |= scan_bitmask; + } + } + if (cinfo->Al > 10) { + return JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al); + } +} + +// Reads the Define Huffman Table (DHT) marker segment and builds the Huffman +// decoding table in either dc_huff_lut_ or ac_huff_lut_, depending on the type +// and solt_id of Huffman code being read. +void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + size_t pos = 2; + if (pos == len) { + return JPEGLI_ERROR("DHT marker: no Huffman table found"); + } + while (pos < len) { + JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength); + // The index of the Huffman code in the current set of Huffman codes. For AC + // component Huffman codes, 0x10 is added to the index. + int slot_id = ReadUint8(data, &pos); + int huffman_index = slot_id; + int is_ac_table = (slot_id & 0x10) != 0; + JHUFF_TBL** table; + if (is_ac_table) { + huffman_index -= 0x10; + JPEG_VERIFY_INPUT(huffman_index, 0, NUM_HUFF_TBLS - 1); + table = &cinfo->ac_huff_tbl_ptrs[huffman_index]; + } else { + JPEG_VERIFY_INPUT(huffman_index, 0, NUM_HUFF_TBLS - 1); + table = &cinfo->dc_huff_tbl_ptrs[huffman_index]; + } + if (*table == nullptr) { + *table = jpegli_alloc_huff_table(reinterpret_cast(cinfo)); + } + int total_count = 0; + for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) { + int count = ReadUint8(data, &pos); + (*table)->bits[i] = count; + total_count += count; + } + if (is_ac_table) { + JPEG_VERIFY_INPUT(total_count, 0, kJpegHuffmanAlphabetSize); + } else { + // Allow symbols up to 15 here, we check later whether any invalid symbols + // are actually decoded. + // TODO(szabadka) Make sure decoder works (does not crash) with up to + // 15-nbits DC symbols and then increase kJpegDCAlphabetSize. + JPEG_VERIFY_INPUT(total_count, 0, 16); + } + JPEG_VERIFY_LEN(total_count); + for (int i = 0; i < total_count; ++i) { + int value = ReadUint8(data, &pos); + if (!is_ac_table) { + JPEG_VERIFY_INPUT(value, 0, 15); + } + (*table)->huffval[i] = value; + } + for (int i = total_count; i < kJpegHuffmanAlphabetSize; ++i) { + (*table)->huffval[i] = 0; + } + } + JPEG_VERIFY_MARKER_END(); +} + +void ProcessDQT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + jpeg_decomp_master* m = cinfo->master; + if (m->found_sof_) { + JPEGLI_ERROR("Updating quant tables between scans is not supported."); + } + size_t pos = 2; + if (pos == len) { + return JPEGLI_ERROR("DQT marker: no quantization table found"); + } + while (pos < len) { + JPEG_VERIFY_LEN(1); + int quant_table_index = ReadUint8(data, &pos); + int precision = quant_table_index >> 4; + JPEG_VERIFY_INPUT(precision, 0, 1); + quant_table_index &= 0xf; + JPEG_VERIFY_INPUT(quant_table_index, 0, NUM_QUANT_TBLS - 1); + JPEG_VERIFY_LEN((precision + 1) * DCTSIZE2); + + if (cinfo->quant_tbl_ptrs[quant_table_index] == nullptr) { + cinfo->quant_tbl_ptrs[quant_table_index] = + jpegli_alloc_quant_table(reinterpret_cast(cinfo)); + } + JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[quant_table_index]; + + for (size_t i = 0; i < DCTSIZE2; ++i) { + int quant_val = + precision ? ReadUint16(data, &pos) : ReadUint8(data, &pos); + JPEG_VERIFY_INPUT(quant_val, 1, 65535); + quant_table->quantval[kJPEGNaturalOrder[i]] = quant_val; + } + } + JPEG_VERIFY_MARKER_END(); +} + +void ProcessDNL(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + // Ignore marker. +} + +void ProcessDRI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + jpeg_decomp_master* m = cinfo->master; + if (m->found_dri_) { + return JPEGLI_ERROR("Duplicate DRI marker."); + } + m->found_dri_ = true; + size_t pos = 2; + JPEG_VERIFY_LEN(2); + cinfo->restart_interval = ReadUint16(data, &pos); + JPEG_VERIFY_MARKER_END(); +} + +void ProcessAPP(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + jpeg_decomp_master* m = cinfo->master; + const uint8_t marker = cinfo->unread_marker; + const uint8_t* payload = data + 2; + size_t payload_size = len - 2; + if (marker == 0xE0) { + if (payload_size >= 14 && memcmp(payload, "JFIF", 4) == 0) { + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = payload[5]; + cinfo->JFIF_minor_version = payload[6]; + cinfo->density_unit = payload[7]; + cinfo->X_density = (payload[8] << 8) + payload[9]; + cinfo->Y_density = (payload[10] << 8) + payload[11]; + } + } else if (marker == 0xEE) { + if (payload_size >= 12 && memcmp(payload, "Adobe", 5) == 0) { + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = payload[11]; + } + } else if (marker == 0xE2) { + if (payload_size >= sizeof(kIccProfileTag) && + memcmp(payload, kIccProfileTag, sizeof(kIccProfileTag)) == 0) { + payload += sizeof(kIccProfileTag); + payload_size -= sizeof(kIccProfileTag); + if (payload_size < 2) { + return JPEGLI_ERROR("ICC chunk is too small."); + } + uint8_t index = payload[0]; + uint8_t total = payload[1]; + ++m->icc_index_; + if (m->icc_index_ != index) { + return JPEGLI_ERROR("Invalid ICC chunk order."); + } + if (total == 0) { + return JPEGLI_ERROR("Invalid ICC chunk total."); + } + if (m->icc_total_ == 0) { + m->icc_total_ = total; + } else if (m->icc_total_ != total) { + return JPEGLI_ERROR("Invalid ICC chunk total."); + } + if (m->icc_index_ > m->icc_total_) { + return JPEGLI_ERROR("Invalid ICC chunk index."); + } + m->icc_profile_.insert(m->icc_profile_.end(), payload + 2, + payload + payload_size); + } + } +} + +void ProcessCOM(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + // Ignore marker. +} + +void ProcessSOI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + jpeg_decomp_master* m = cinfo->master; + if (m->found_soi_) { + JPEGLI_ERROR("Duplicate SOI marker"); + } + m->found_soi_ = true; +} + +void ProcessEOI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + cinfo->master->found_eoi_ = true; +} + +void SaveMarker(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { + const uint8_t marker = cinfo->unread_marker; + const uint8_t* payload = data + 2; + size_t payload_size = len - 2; + + // Insert new saved marker to the head of the list. + jpeg_saved_marker_ptr next = cinfo->marker_list; + cinfo->marker_list = + jpegli::Allocate(cinfo, 1, JPOOL_IMAGE); + cinfo->marker_list->next = next; + cinfo->marker_list->marker = marker; + cinfo->marker_list->original_length = payload_size; + cinfo->marker_list->data_length = payload_size; + cinfo->marker_list->data = + jpegli::Allocate(cinfo, payload_size, JPOOL_IMAGE); + memcpy(cinfo->marker_list->data, payload, payload_size); +} + +uint8_t ProcessNextMarker(j_decompress_ptr cinfo, const uint8_t* const data, + const size_t len, size_t* pos) { + jpeg_decomp_master* m = cinfo->master; + size_t num_skipped = 0; + uint8_t marker = cinfo->unread_marker; + if (marker == 0) { + // kIsValidMarker[i] == 1 means (0xc0 + i) is a valid marker. + static const uint8_t kIsValidMarker[] = { + 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + }; + // Skip bytes between markers. + while (*pos + 1 < len && (data[*pos] != 0xff || data[*pos + 1] < 0xc0 || + !kIsValidMarker[data[*pos + 1] - 0xc0])) { + ++(*pos); + ++num_skipped; + } + if (*pos + 2 > len) { + return kNeedMoreInput; + } + marker = data[*pos + 1]; + if (num_skipped > 0) { + if (m->found_soi_) { + JPEGLI_WARN("Skipped %d bytes before marker 0x%02x", (int)num_skipped, + marker); + } else { + JPEGLI_ERROR("Did not find SOI marker."); + } + } + *pos += 2; + cinfo->unread_marker = marker; + } + if (!m->found_soi_ && marker != 0xd8) { + JPEGLI_ERROR("Did not find SOI marker."); + } + if (GetMarkerProcessor(cinfo)) { + return kHandleMarkerProcessor; + } + const uint8_t* marker_data = &data[*pos]; + size_t marker_len = 0; + if (marker != 0xd8 && marker != 0xd9) { + if (*pos + 2 > len) { + return kNeedMoreInput; + } + marker_len += (data[*pos] << 8) + data[*pos + 1]; + if (marker_len < 2) { + JPEGLI_ERROR("Invalid marker length"); + } + if (*pos + marker_len > len) { + // TODO(szabadka) Limit our memory usage by using the skip_input_data + // source manager callback on APP markers that are not saved. + return kNeedMoreInput; + } + if (marker >= 0xe0 && m->markers_to_save_[marker - 0xe0]) { + SaveMarker(cinfo, marker_data, marker_len); + } + } + if (marker == 0xc0 || marker == 0xc1 || marker == 0xc2) { + ProcessSOF(cinfo, marker_data, marker_len); + } else if (marker == 0xc4) { + ProcessDHT(cinfo, marker_data, marker_len); + } else if (marker == 0xda) { + ProcessSOS(cinfo, marker_data, marker_len); + } else if (marker == 0xdb) { + ProcessDQT(cinfo, marker_data, marker_len); + } else if (marker == 0xdc) { + ProcessDNL(cinfo, marker_data, marker_len); + } else if (marker == 0xdd) { + ProcessDRI(cinfo, marker_data, marker_len); + } else if (marker >= 0xe0 && marker <= 0xef) { + ProcessAPP(cinfo, marker_data, marker_len); + } else if (marker == 0xfe) { + ProcessCOM(cinfo, marker_data, marker_len); + } else if (marker == 0xd8) { + ProcessSOI(cinfo, marker_data, marker_len); + } else if (marker == 0xd9) { + ProcessEOI(cinfo, marker_data, marker_len); + } else { + JPEGLI_ERROR("Unexpected marker 0x%x", marker); + } + *pos += marker_len; + cinfo->unread_marker = 0; + if (marker == 0xda) { + return JPEG_REACHED_SOS; + } else if (marker == 0xd9) { + return JPEG_REACHED_EOI; + } + return kProcessNextMarker; +} + +} // namespace + +jpeg_marker_parser_method GetMarkerProcessor(j_decompress_ptr cinfo) { + jpeg_decomp_master* m = cinfo->master; + uint8_t marker = cinfo->unread_marker; + jpeg_marker_parser_method callback = nullptr; + if (marker >= 0xe0 && marker <= 0xef) { + callback = m->app_marker_parsers[marker - 0xe0]; + } else if (marker == 0xfe) { + callback = m->com_marker_parser; + } + return callback; +} + +int ProcessMarkers(j_decompress_ptr cinfo, const uint8_t* const data, + const size_t len, size_t* pos) { + for (;;) { + int status = ProcessNextMarker(cinfo, data, len, pos); + if (status != kProcessNextMarker) { + return status; + } + } +} + +} // namespace jpegli -- cgit v1.2.3