tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

decode_marker.cc (20970B)


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