libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

decode_marker.cc (21285B)


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