libjxl

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

error_handling_test.cc (41253B)


      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.h"
      7 #include "lib/jpegli/encode.h"
      8 #include "lib/jpegli/error.h"
      9 #include "lib/jpegli/test_utils.h"
     10 #include "lib/jpegli/testing.h"
     11 #include "lib/jxl/sanitizers.h"
     12 
     13 namespace jpegli {
     14 namespace {
     15 
     16 TEST(EncoderErrorHandlingTest, MinimalSuccess) {
     17   uint8_t* buffer = nullptr;
     18   unsigned long buffer_size = 0;
     19   {
     20     jpeg_compress_struct cinfo;
     21     const auto try_catch_block = [&]() -> bool {
     22       ERROR_HANDLER_SETUP(jpegli);
     23       jpegli_create_compress(&cinfo);
     24       jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
     25       cinfo.image_width = 1;
     26       cinfo.image_height = 1;
     27       cinfo.input_components = 1;
     28       jpegli_set_defaults(&cinfo);
     29       jpegli_start_compress(&cinfo, TRUE);
     30       JSAMPLE image[1] = {0};
     31       JSAMPROW row[] = {image};
     32       jpegli_write_scanlines(&cinfo, row, 1);
     33       jpegli_finish_compress(&cinfo);
     34       return true;
     35     };
     36     EXPECT_TRUE(try_catch_block());
     37     jpegli_destroy_compress(&cinfo);
     38   }
     39   TestImage output;
     40   DecodeWithLibjpeg(CompressParams(), DecompressParams(), nullptr, 0, buffer,
     41                     buffer_size, &output);
     42   EXPECT_EQ(1, output.xsize);
     43   EXPECT_EQ(1, output.ysize);
     44   EXPECT_EQ(1, output.components);
     45   EXPECT_EQ(0, output.pixels[0]);
     46   if (buffer) free(buffer);
     47 }
     48 
     49 TEST(EncoderErrorHandlingTest, NoDestination) {
     50   jpeg_compress_struct cinfo;
     51   const auto try_catch_block = [&]() -> bool {
     52     ERROR_HANDLER_SETUP(jpegli);
     53     jpegli_create_compress(&cinfo);
     54     cinfo.image_width = 1;
     55     cinfo.image_height = 1;
     56     cinfo.input_components = 1;
     57     jpegli_set_defaults(&cinfo);
     58     jpegli_start_compress(&cinfo, TRUE);
     59     return true;
     60   };
     61   EXPECT_FALSE(try_catch_block());
     62   jpegli_destroy_compress(&cinfo);
     63 }
     64 
     65 TEST(EncoderErrorHandlingTest, NoImageDimensions) {
     66   uint8_t* buffer = nullptr;
     67   unsigned long buffer_size = 0;
     68   jpeg_compress_struct cinfo;
     69   const auto try_catch_block = [&]() -> bool {
     70     ERROR_HANDLER_SETUP(jpegli);
     71     jpegli_create_compress(&cinfo);
     72     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
     73     cinfo.input_components = 1;
     74     jpegli_set_defaults(&cinfo);
     75     jpegli_start_compress(&cinfo, TRUE);
     76     return true;
     77   };
     78   EXPECT_FALSE(try_catch_block());
     79   jpegli_destroy_compress(&cinfo);
     80   if (buffer) free(buffer);
     81 }
     82 
     83 TEST(EncoderErrorHandlingTest, ImageTooBig) {
     84   uint8_t* buffer = nullptr;
     85   unsigned long buffer_size = 0;
     86   jpeg_compress_struct cinfo;
     87   const auto try_catch_block = [&]() -> bool {
     88     ERROR_HANDLER_SETUP(jpegli);
     89     jpegli_create_compress(&cinfo);
     90     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
     91     cinfo.image_width = 100000;
     92     cinfo.image_height = 1;
     93     cinfo.input_components = 1;
     94     jpegli_set_defaults(&cinfo);
     95     jpegli_start_compress(&cinfo, TRUE);
     96     return true;
     97   };
     98   EXPECT_FALSE(try_catch_block());
     99   jpegli_destroy_compress(&cinfo);
    100   if (buffer) free(buffer);
    101 }
    102 
    103 TEST(EncoderErrorHandlingTest, NoInputComponents) {
    104   uint8_t* buffer = nullptr;
    105   unsigned long buffer_size = 0;
    106   jpeg_compress_struct cinfo;
    107   const auto try_catch_block = [&]() -> bool {
    108     ERROR_HANDLER_SETUP(jpegli);
    109     jpegli_create_compress(&cinfo);
    110     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    111     cinfo.image_width = 1;
    112     cinfo.image_height = 1;
    113     jpegli_set_defaults(&cinfo);
    114     jpegli_start_compress(&cinfo, TRUE);
    115     return true;
    116   };
    117   EXPECT_FALSE(try_catch_block());
    118   jpegli_destroy_compress(&cinfo);
    119   if (buffer) free(buffer);
    120 }
    121 
    122 TEST(EncoderErrorHandlingTest, TooManyInputComponents) {
    123   uint8_t* buffer = nullptr;
    124   unsigned long buffer_size = 0;
    125   jpeg_compress_struct cinfo;
    126   const auto try_catch_block = [&]() -> bool {
    127     ERROR_HANDLER_SETUP(jpegli);
    128     jpegli_create_compress(&cinfo);
    129     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    130     cinfo.image_width = 1;
    131     cinfo.image_height = 1;
    132     cinfo.input_components = 1000;
    133     jpegli_set_defaults(&cinfo);
    134     jpegli_start_compress(&cinfo, TRUE);
    135     return true;
    136   };
    137   EXPECT_FALSE(try_catch_block());
    138   jpegli_destroy_compress(&cinfo);
    139   if (buffer) free(buffer);
    140 }
    141 
    142 TEST(EncoderErrorHandlingTest, NoSetDefaults) {
    143   uint8_t* buffer = nullptr;
    144   unsigned long buffer_size = 0;
    145   jpeg_compress_struct cinfo;
    146   const auto try_catch_block = [&]() -> bool {
    147     ERROR_HANDLER_SETUP(jpegli);
    148     jpegli_create_compress(&cinfo);
    149     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    150     cinfo.image_width = 1;
    151     cinfo.image_height = 1;
    152     cinfo.input_components = 1;
    153     jpegli_start_compress(&cinfo, TRUE);
    154     JSAMPLE image[1] = {0};
    155     JSAMPROW row[] = {image};
    156     jpegli_write_scanlines(&cinfo, row, 1);
    157     jpegli_finish_compress(&cinfo);
    158     return true;
    159   };
    160   EXPECT_FALSE(try_catch_block());
    161   jpegli_destroy_compress(&cinfo);
    162   if (buffer) free(buffer);
    163 }
    164 
    165 TEST(EncoderErrorHandlingTest, NoStartCompress) {
    166   uint8_t* buffer = nullptr;
    167   unsigned long buffer_size = 0;
    168   jpeg_compress_struct cinfo;
    169   const auto try_catch_block = [&]() -> bool {
    170     ERROR_HANDLER_SETUP(jpegli);
    171     jpegli_create_compress(&cinfo);
    172     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    173     cinfo.image_width = 1;
    174     cinfo.image_height = 1;
    175     cinfo.input_components = 1;
    176     jpegli_set_defaults(&cinfo);
    177     JSAMPLE image[1] = {0};
    178     JSAMPROW row[] = {image};
    179     jpegli_write_scanlines(&cinfo, row, 1);
    180     return true;
    181   };
    182   EXPECT_FALSE(try_catch_block());
    183   jpegli_destroy_compress(&cinfo);
    184   if (buffer) free(buffer);
    185 }
    186 
    187 TEST(EncoderErrorHandlingTest, NoWriteScanlines) {
    188   uint8_t* buffer = nullptr;
    189   unsigned long buffer_size = 0;
    190   jpeg_compress_struct cinfo;
    191   const auto try_catch_block = [&]() -> bool {
    192     ERROR_HANDLER_SETUP(jpegli);
    193     jpegli_create_compress(&cinfo);
    194     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    195     cinfo.image_width = 1;
    196     cinfo.image_height = 1;
    197     cinfo.input_components = 1;
    198     jpegli_set_defaults(&cinfo);
    199     jpegli_start_compress(&cinfo, TRUE);
    200     jpegli_finish_compress(&cinfo);
    201     return true;
    202   };
    203   EXPECT_FALSE(try_catch_block());
    204   jpegli_destroy_compress(&cinfo);
    205   if (buffer) free(buffer);
    206 }
    207 
    208 TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) {
    209   uint8_t* buffer = nullptr;
    210   unsigned long buffer_size = 0;
    211   jpeg_compress_struct cinfo;
    212   const auto try_catch_block = [&]() -> bool {
    213     ERROR_HANDLER_SETUP(jpegli);
    214     jpegli_create_compress(&cinfo);
    215     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    216     cinfo.image_width = 1;
    217     cinfo.image_height = 2;
    218     cinfo.input_components = 1;
    219     jpegli_set_defaults(&cinfo);
    220     jpegli_start_compress(&cinfo, TRUE);
    221     JSAMPLE image[1] = {0};
    222     JSAMPROW row[] = {image};
    223     jpegli_write_scanlines(&cinfo, row, 1);
    224     jpegli_finish_compress(&cinfo);
    225     return true;
    226   };
    227   EXPECT_FALSE(try_catch_block());
    228   jpegli_destroy_compress(&cinfo);
    229   if (buffer) free(buffer);
    230 }
    231 
    232 TEST(EncoderErrorHandlingTest, InvalidQuantValue) {
    233   uint8_t* buffer = nullptr;
    234   unsigned long buffer_size = 0;
    235   jpeg_compress_struct cinfo;
    236   const auto try_catch_block = [&]() -> bool {
    237     ERROR_HANDLER_SETUP(jpegli);
    238     jpegli_create_compress(&cinfo);
    239     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    240     cinfo.image_width = 1;
    241     cinfo.image_height = 1;
    242     cinfo.input_components = 1;
    243     jpegli_set_defaults(&cinfo);
    244     cinfo.quant_tbl_ptrs[0] =
    245         jpegli_alloc_quant_table(reinterpret_cast<j_common_ptr>(&cinfo));
    246     for (UINT16& q : cinfo.quant_tbl_ptrs[0]->quantval) {
    247       q = 0;
    248     }
    249     jpegli_start_compress(&cinfo, TRUE);
    250     JSAMPLE image[1] = {0};
    251     JSAMPROW row[] = {image};
    252     jpegli_write_scanlines(&cinfo, row, 1);
    253     jpegli_finish_compress(&cinfo);
    254     return true;
    255   };
    256   EXPECT_FALSE(try_catch_block());
    257   jpegli_destroy_compress(&cinfo);
    258   if (buffer) free(buffer);
    259 }
    260 
    261 TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) {
    262   uint8_t* buffer = nullptr;
    263   unsigned long buffer_size = 0;
    264   jpeg_compress_struct cinfo;
    265   const auto try_catch_block = [&]() -> bool {
    266     ERROR_HANDLER_SETUP(jpegli);
    267     jpegli_create_compress(&cinfo);
    268     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    269     cinfo.image_width = 1;
    270     cinfo.image_height = 1;
    271     cinfo.input_components = 1;
    272     jpegli_set_defaults(&cinfo);
    273     cinfo.comp_info[0].quant_tbl_no = 3;
    274     jpegli_start_compress(&cinfo, TRUE);
    275     JSAMPLE image[1] = {0};
    276     JSAMPROW row[] = {image};
    277     jpegli_write_scanlines(&cinfo, row, 1);
    278     jpegli_finish_compress(&cinfo);
    279     return true;
    280   };
    281   EXPECT_FALSE(try_catch_block());
    282   jpegli_destroy_compress(&cinfo);
    283   if (buffer) free(buffer);
    284 }
    285 
    286 TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) {
    287   uint8_t* buffer = nullptr;
    288   unsigned long buffer_size = 0;
    289   jpeg_compress_struct cinfo;
    290   const auto try_catch_block = [&]() -> bool {
    291     ERROR_HANDLER_SETUP(jpegli);
    292     jpegli_create_compress(&cinfo);
    293     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    294     cinfo.image_width = 1;
    295     cinfo.image_height = 1;
    296     cinfo.input_components = 1;
    297     jpegli_set_defaults(&cinfo);
    298     cinfo.num_components = 100;
    299     jpegli_start_compress(&cinfo, TRUE);
    300     return true;
    301   };
    302   EXPECT_FALSE(try_catch_block());
    303   jpegli_destroy_compress(&cinfo);
    304   if (buffer) free(buffer);
    305 }
    306 
    307 TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) {
    308   uint8_t* buffer = nullptr;
    309   unsigned long buffer_size = 0;
    310   jpeg_compress_struct cinfo;
    311   const auto try_catch_block = [&]() -> bool {
    312     ERROR_HANDLER_SETUP(jpegli);
    313     jpegli_create_compress(&cinfo);
    314     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    315     cinfo.image_width = 1;
    316     cinfo.image_height = 1;
    317     cinfo.input_components = 1;
    318     jpegli_set_defaults(&cinfo);
    319     cinfo.num_components = 2;
    320     jpegli_start_compress(&cinfo, TRUE);
    321     return true;
    322   };
    323   EXPECT_FALSE(try_catch_block());
    324   jpegli_destroy_compress(&cinfo);
    325   if (buffer) free(buffer);
    326 }
    327 
    328 TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) {
    329   uint8_t* buffer = nullptr;
    330   unsigned long buffer_size = 0;
    331   jpeg_compress_struct cinfo;
    332   const auto try_catch_block = [&]() -> bool {
    333     ERROR_HANDLER_SETUP(jpegli);
    334     jpegli_create_compress(&cinfo);
    335     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    336     cinfo.image_width = 1;
    337     cinfo.image_height = 1;
    338     cinfo.input_components = 1;
    339     jpegli_set_defaults(&cinfo);
    340     cinfo.num_components = 2;
    341     cinfo.comp_info[1].h_samp_factor = cinfo.comp_info[1].v_samp_factor = 1;
    342     jpegli_start_compress(&cinfo, TRUE);
    343     JSAMPLE image[1] = {0};
    344     JSAMPROW row[] = {image};
    345     jpegli_write_scanlines(&cinfo, row, 1);
    346     jpegli_finish_compress(&cinfo);
    347     return true;
    348   };
    349   EXPECT_FALSE(try_catch_block());
    350   jpegli_destroy_compress(&cinfo);
    351   if (buffer) free(buffer);
    352 }
    353 
    354 TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) {
    355   uint8_t* buffer = nullptr;
    356   unsigned long buffer_size = 0;
    357   jpeg_compress_struct cinfo;
    358   const auto try_catch_block = [&]() -> bool {
    359     ERROR_HANDLER_SETUP(jpegli);
    360     jpegli_create_compress(&cinfo);
    361     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    362     cinfo.image_width = 1;
    363     cinfo.image_height = 1;
    364     cinfo.input_components = 1;
    365     cinfo.in_color_space = JCS_RGB;
    366     jpegli_set_defaults(&cinfo);
    367     jpegli_start_compress(&cinfo, TRUE);
    368     JSAMPLE image[1] = {0};
    369     JSAMPROW row[] = {image};
    370     jpegli_write_scanlines(&cinfo, row, 1);
    371     jpegli_finish_compress(&cinfo);
    372     return true;
    373   };
    374   EXPECT_FALSE(try_catch_block());
    375   jpegli_destroy_compress(&cinfo);
    376   if (buffer) free(buffer);
    377 }
    378 
    379 TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) {
    380   uint8_t* buffer = nullptr;
    381   unsigned long buffer_size = 0;
    382   jpeg_compress_struct cinfo;
    383   const auto try_catch_block = [&]() -> bool {
    384     ERROR_HANDLER_SETUP(jpegli);
    385     jpegli_create_compress(&cinfo);
    386     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    387     cinfo.image_width = 1;
    388     cinfo.image_height = 1;
    389     cinfo.input_components = 3;
    390     cinfo.in_color_space = JCS_GRAYSCALE;
    391     jpegli_set_defaults(&cinfo);
    392     jpegli_start_compress(&cinfo, TRUE);
    393     JSAMPLE image[3] = {0};
    394     JSAMPROW row[] = {image};
    395     jpegli_write_scanlines(&cinfo, row, 1);
    396     jpegli_finish_compress(&cinfo);
    397     return true;
    398   };
    399   EXPECT_FALSE(try_catch_block());
    400   jpegli_destroy_compress(&cinfo);
    401   if (buffer) free(buffer);
    402 }
    403 
    404 TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) {
    405   uint8_t* buffer = nullptr;
    406   unsigned long buffer_size = 0;
    407   jpeg_compress_struct cinfo;
    408   const auto try_catch_block = [&]() -> bool {
    409     ERROR_HANDLER_SETUP(jpegli);
    410     jpegli_create_compress(&cinfo);
    411     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    412     cinfo.image_width = 1;
    413     cinfo.image_height = 1;
    414     cinfo.input_components = 3;
    415     cinfo.in_color_space = JCS_RGB;
    416     jpegli_set_defaults(&cinfo);
    417     cinfo.num_components = 2;
    418     jpegli_start_compress(&cinfo, TRUE);
    419     JSAMPLE image[3] = {0};
    420     JSAMPROW row[] = {image};
    421     jpegli_write_scanlines(&cinfo, row, 1);
    422     jpegli_finish_compress(&cinfo);
    423     return true;
    424   };
    425   EXPECT_FALSE(try_catch_block());
    426   jpegli_destroy_compress(&cinfo);
    427   if (buffer) free(buffer);
    428 }
    429 
    430 TEST(EncoderErrorHandlingTest, InvalidColorTransform) {
    431   uint8_t* buffer = nullptr;
    432   unsigned long buffer_size = 0;
    433   jpeg_compress_struct cinfo;
    434   const auto try_catch_block = [&]() -> bool {
    435     ERROR_HANDLER_SETUP(jpegli);
    436     jpegli_create_compress(&cinfo);
    437     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    438     cinfo.image_width = 1;
    439     cinfo.image_height = 1;
    440     cinfo.input_components = 3;
    441     cinfo.in_color_space = JCS_YCbCr;
    442     jpegli_set_defaults(&cinfo);
    443     cinfo.jpeg_color_space = JCS_RGB;
    444     jpegli_start_compress(&cinfo, TRUE);
    445     JSAMPLE image[3] = {0};
    446     JSAMPROW row[] = {image};
    447     jpegli_write_scanlines(&cinfo, row, 1);
    448     jpegli_finish_compress(&cinfo);
    449     return true;
    450   };
    451   EXPECT_FALSE(try_catch_block());
    452   jpegli_destroy_compress(&cinfo);
    453   if (buffer) free(buffer);
    454 }
    455 
    456 TEST(EncoderErrorHandlingTest, DuplicateComponentIds) {
    457   uint8_t* buffer = nullptr;
    458   unsigned long buffer_size = 0;
    459   jpeg_compress_struct cinfo;
    460   const auto try_catch_block = [&]() -> bool {
    461     ERROR_HANDLER_SETUP(jpegli);
    462     jpegli_create_compress(&cinfo);
    463     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    464     cinfo.image_width = 1;
    465     cinfo.image_height = 1;
    466     cinfo.input_components = 3;
    467     jpegli_set_defaults(&cinfo);
    468     cinfo.comp_info[0].component_id = 0;
    469     cinfo.comp_info[1].component_id = 0;
    470     jpegli_start_compress(&cinfo, TRUE);
    471     return true;
    472   };
    473   EXPECT_FALSE(try_catch_block());
    474   jpegli_destroy_compress(&cinfo);
    475   if (buffer) free(buffer);
    476 }
    477 
    478 TEST(EncoderErrorHandlingTest, InvalidComponentIndex) {
    479   uint8_t* buffer = nullptr;
    480   unsigned long buffer_size = 0;
    481   jpeg_compress_struct cinfo;
    482   const auto try_catch_block = [&]() -> bool {
    483     ERROR_HANDLER_SETUP(jpegli);
    484     jpegli_create_compress(&cinfo);
    485     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    486     cinfo.image_width = 1;
    487     cinfo.image_height = 1;
    488     cinfo.input_components = 3;
    489     jpegli_set_defaults(&cinfo);
    490     cinfo.comp_info[0].component_index = 17;
    491     jpegli_start_compress(&cinfo, TRUE);
    492     return true;
    493   };
    494   EXPECT_FALSE(try_catch_block());
    495   jpegli_destroy_compress(&cinfo);
    496   if (buffer) free(buffer);
    497 }
    498 
    499 TEST(EncoderErrorHandlingTest, ArithmeticCoding) {
    500   uint8_t* buffer = nullptr;
    501   unsigned long buffer_size = 0;
    502   jpeg_compress_struct cinfo;
    503   const auto try_catch_block = [&]() -> bool {
    504     ERROR_HANDLER_SETUP(jpegli);
    505     jpegli_create_compress(&cinfo);
    506     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    507     cinfo.image_width = 1;
    508     cinfo.image_height = 1;
    509     cinfo.input_components = 3;
    510     jpegli_set_defaults(&cinfo);
    511     cinfo.arith_code = TRUE;
    512     jpegli_start_compress(&cinfo, TRUE);
    513     return true;
    514   };
    515   EXPECT_FALSE(try_catch_block());
    516   jpegli_destroy_compress(&cinfo);
    517   if (buffer) free(buffer);
    518 }
    519 
    520 TEST(EncoderErrorHandlingTest, CCIR601Sampling) {
    521   uint8_t* buffer = nullptr;
    522   unsigned long buffer_size = 0;
    523   jpeg_compress_struct cinfo;
    524   const auto try_catch_block = [&]() -> bool {
    525     ERROR_HANDLER_SETUP(jpegli);
    526     jpegli_create_compress(&cinfo);
    527     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    528     cinfo.image_width = 1;
    529     cinfo.image_height = 1;
    530     cinfo.input_components = 3;
    531     jpegli_set_defaults(&cinfo);
    532     cinfo.CCIR601_sampling = TRUE;
    533     jpegli_start_compress(&cinfo, TRUE);
    534     return true;
    535   };
    536   EXPECT_FALSE(try_catch_block());
    537   jpegli_destroy_compress(&cinfo);
    538   if (buffer) free(buffer);
    539 }
    540 
    541 TEST(EncoderErrorHandlingTest, InvalidScanScript1) {
    542   uint8_t* buffer = nullptr;
    543   unsigned long buffer_size = 0;
    544   jpeg_compress_struct cinfo;
    545   const auto try_catch_block = [&]() -> bool {
    546     ERROR_HANDLER_SETUP(jpegli);
    547     jpegli_create_compress(&cinfo);
    548     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    549     cinfo.image_width = 1;
    550     cinfo.image_height = 1;
    551     cinfo.input_components = 1;
    552     jpegli_set_defaults(&cinfo);
    553     static constexpr jpeg_scan_info kScript[] = {{1, {0}, 0, 63, 0, 0}};  //
    554     cinfo.scan_info = kScript;
    555     cinfo.num_scans = 0;
    556     jpegli_start_compress(&cinfo, TRUE);
    557     return true;
    558   };
    559   EXPECT_FALSE(try_catch_block());
    560   jpegli_destroy_compress(&cinfo);
    561   if (buffer) free(buffer);
    562 }
    563 
    564 TEST(EncoderErrorHandlingTest, InvalidScanScript2) {
    565   uint8_t* buffer = nullptr;
    566   unsigned long buffer_size = 0;
    567   jpeg_compress_struct cinfo;
    568   const auto try_catch_block = [&]() -> bool {
    569     ERROR_HANDLER_SETUP(jpegli);
    570     jpegli_create_compress(&cinfo);
    571     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    572     cinfo.image_width = 1;
    573     cinfo.image_height = 1;
    574     cinfo.input_components = 1;
    575     jpegli_set_defaults(&cinfo);
    576     static constexpr jpeg_scan_info kScript[] = {{2, {0, 1}, 0, 63, 0, 0}};  //
    577     cinfo.scan_info = kScript;
    578     cinfo.num_scans = ARRAY_SIZE(kScript);
    579     jpegli_start_compress(&cinfo, TRUE);
    580     return true;
    581   };
    582   EXPECT_FALSE(try_catch_block());
    583   jpegli_destroy_compress(&cinfo);
    584   if (buffer) free(buffer);
    585 }
    586 
    587 TEST(EncoderErrorHandlingTest, InvalidScanScript3) {
    588   uint8_t* buffer = nullptr;
    589   unsigned long buffer_size = 0;
    590   jpeg_compress_struct cinfo;
    591   const auto try_catch_block = [&]() -> bool {
    592     ERROR_HANDLER_SETUP(jpegli);
    593     jpegli_create_compress(&cinfo);
    594     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    595     cinfo.image_width = 1;
    596     cinfo.image_height = 1;
    597     cinfo.input_components = 1;
    598     jpegli_set_defaults(&cinfo);
    599     static constexpr jpeg_scan_info kScript[] = {{5, {0}, 0, 63, 0, 0}};  //
    600     cinfo.scan_info = kScript;
    601     cinfo.num_scans = ARRAY_SIZE(kScript);
    602     jpegli_start_compress(&cinfo, TRUE);
    603     return true;
    604   };
    605   EXPECT_FALSE(try_catch_block());
    606   jpegli_destroy_compress(&cinfo);
    607   if (buffer) free(buffer);
    608 }
    609 
    610 TEST(EncoderErrorHandlingTest, InvalidScanScript4) {
    611   uint8_t* buffer = nullptr;
    612   unsigned long buffer_size = 0;
    613   jpeg_compress_struct cinfo;
    614   const auto try_catch_block = [&]() -> bool {
    615     ERROR_HANDLER_SETUP(jpegli);
    616     jpegli_create_compress(&cinfo);
    617     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    618     cinfo.image_width = 1;
    619     cinfo.image_height = 1;
    620     cinfo.input_components = 2;
    621     jpegli_set_defaults(&cinfo);
    622     static constexpr jpeg_scan_info kScript[] = {{2, {0, 0}, 0, 63, 0, 0}};  //
    623     cinfo.scan_info = kScript;
    624     cinfo.num_scans = ARRAY_SIZE(kScript);
    625     jpegli_start_compress(&cinfo, TRUE);
    626     return true;
    627   };
    628   EXPECT_FALSE(try_catch_block());
    629   jpegli_destroy_compress(&cinfo);
    630   if (buffer) free(buffer);
    631 }
    632 
    633 TEST(EncoderErrorHandlingTest, InvalidScanScript5) {
    634   uint8_t* buffer = nullptr;
    635   unsigned long buffer_size = 0;
    636   jpeg_compress_struct cinfo;
    637   const auto try_catch_block = [&]() -> bool {
    638     ERROR_HANDLER_SETUP(jpegli);
    639     jpegli_create_compress(&cinfo);
    640     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    641     cinfo.image_width = 1;
    642     cinfo.image_height = 1;
    643     cinfo.input_components = 2;
    644     jpegli_set_defaults(&cinfo);
    645     static constexpr jpeg_scan_info kScript[] = {{2, {1, 0}, 0, 63, 0, 0}};  //
    646     cinfo.scan_info = kScript;
    647     cinfo.num_scans = ARRAY_SIZE(kScript);
    648     jpegli_start_compress(&cinfo, TRUE);
    649     return true;
    650   };
    651   EXPECT_FALSE(try_catch_block());
    652   jpegli_destroy_compress(&cinfo);
    653   if (buffer) free(buffer);
    654 }
    655 
    656 TEST(EncoderErrorHandlingTest, InvalidScanScript6) {
    657   uint8_t* buffer = nullptr;
    658   unsigned long buffer_size = 0;
    659   jpeg_compress_struct cinfo;
    660   const auto try_catch_block = [&]() -> bool {
    661     ERROR_HANDLER_SETUP(jpegli);
    662     jpegli_create_compress(&cinfo);
    663     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    664     cinfo.image_width = 1;
    665     cinfo.image_height = 1;
    666     cinfo.input_components = 1;
    667     jpegli_set_defaults(&cinfo);
    668     static constexpr jpeg_scan_info kScript[] = {{1, {0}, 0, 64, 0, 0}};  //
    669     cinfo.scan_info = kScript;
    670     cinfo.num_scans = ARRAY_SIZE(kScript);
    671     jpegli_start_compress(&cinfo, TRUE);
    672     return true;
    673   };
    674   EXPECT_FALSE(try_catch_block());
    675   jpegli_destroy_compress(&cinfo);
    676   if (buffer) free(buffer);
    677 }
    678 
    679 TEST(EncoderErrorHandlingTest, InvalidScanScript7) {
    680   uint8_t* buffer = nullptr;
    681   unsigned long buffer_size = 0;
    682   jpeg_compress_struct cinfo;
    683   const auto try_catch_block = [&]() -> bool {
    684     ERROR_HANDLER_SETUP(jpegli);
    685     jpegli_create_compress(&cinfo);
    686     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    687     cinfo.image_width = 1;
    688     cinfo.image_height = 1;
    689     cinfo.input_components = 1;
    690     jpegli_set_defaults(&cinfo);
    691     static constexpr jpeg_scan_info kScript[] = {{1, {0}, 2, 1, 0, 0}};  //
    692     cinfo.scan_info = kScript;
    693     cinfo.num_scans = ARRAY_SIZE(kScript);
    694     jpegli_start_compress(&cinfo, TRUE);
    695     return true;
    696   };
    697   EXPECT_FALSE(try_catch_block());
    698   jpegli_destroy_compress(&cinfo);
    699   if (buffer) free(buffer);
    700 }
    701 
    702 TEST(EncoderErrorHandlingTest, InvalidScanScript8) {
    703   uint8_t* buffer = nullptr;
    704   unsigned long buffer_size = 0;
    705   jpeg_compress_struct cinfo;
    706   const auto try_catch_block = [&]() -> bool {
    707     ERROR_HANDLER_SETUP(jpegli);
    708     jpegli_create_compress(&cinfo);
    709     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    710     cinfo.image_width = 1;
    711     cinfo.image_height = 1;
    712     cinfo.input_components = 2;
    713     jpegli_set_defaults(&cinfo);
    714     static constexpr jpeg_scan_info kScript[] = {
    715         {1, {0}, 0, 63, 0, 0}, {1, {1}, 0, 0, 0, 0}, {1, {1}, 1, 63, 0, 0}  //
    716     };
    717     cinfo.scan_info = kScript;
    718     cinfo.num_scans = ARRAY_SIZE(kScript);
    719     jpegli_start_compress(&cinfo, TRUE);
    720     return true;
    721   };
    722   EXPECT_FALSE(try_catch_block());
    723   jpegli_destroy_compress(&cinfo);
    724   if (buffer) free(buffer);
    725 }
    726 
    727 TEST(EncoderErrorHandlingTest, InvalidScanScript9) {
    728   uint8_t* buffer = nullptr;
    729   unsigned long buffer_size = 0;
    730   jpeg_compress_struct cinfo;
    731   const auto try_catch_block = [&]() -> bool {
    732     ERROR_HANDLER_SETUP(jpegli);
    733     jpegli_create_compress(&cinfo);
    734     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    735     cinfo.image_width = 1;
    736     cinfo.image_height = 1;
    737     cinfo.input_components = 1;
    738     jpegli_set_defaults(&cinfo);
    739     static constexpr jpeg_scan_info kScript[] = {
    740         {1, {0}, 0, 1, 0, 0}, {1, {0}, 2, 63, 0, 0},  //
    741     };
    742     cinfo.scan_info = kScript;
    743     cinfo.num_scans = ARRAY_SIZE(kScript);
    744     jpegli_start_compress(&cinfo, TRUE);
    745     return true;
    746   };
    747   EXPECT_FALSE(try_catch_block());
    748   jpegli_destroy_compress(&cinfo);
    749   if (buffer) free(buffer);
    750 }
    751 
    752 TEST(EncoderErrorHandlingTest, InvalidScanScript10) {
    753   uint8_t* buffer = nullptr;
    754   unsigned long buffer_size = 0;
    755   jpeg_compress_struct cinfo;
    756   const auto try_catch_block = [&]() -> bool {
    757     ERROR_HANDLER_SETUP(jpegli);
    758     jpegli_create_compress(&cinfo);
    759     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    760     cinfo.image_width = 1;
    761     cinfo.image_height = 1;
    762     cinfo.input_components = 2;
    763     jpegli_set_defaults(&cinfo);
    764     static constexpr jpeg_scan_info kScript[] = {
    765         {2, {0, 1}, 0, 0, 0, 0}, {2, {0, 1}, 1, 63, 0, 0}  //
    766     };
    767     cinfo.scan_info = kScript;
    768     cinfo.num_scans = ARRAY_SIZE(kScript);
    769     jpegli_start_compress(&cinfo, TRUE);
    770     return true;
    771   };
    772   EXPECT_FALSE(try_catch_block());
    773   jpegli_destroy_compress(&cinfo);
    774   if (buffer) free(buffer);
    775 }
    776 
    777 TEST(EncoderErrorHandlingTest, InvalidScanScript11) {
    778   uint8_t* buffer = nullptr;
    779   unsigned long buffer_size = 0;
    780   jpeg_compress_struct cinfo;
    781   const auto try_catch_block = [&]() -> bool {
    782     ERROR_HANDLER_SETUP(jpegli);
    783     jpegli_create_compress(&cinfo);
    784     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    785     cinfo.image_width = 1;
    786     cinfo.image_height = 1;
    787     cinfo.input_components = 1;
    788     jpegli_set_defaults(&cinfo);
    789     static constexpr jpeg_scan_info kScript[] = {
    790         {1, {0}, 1, 63, 0, 0}, {1, {0}, 0, 0, 0, 0}  //
    791     };
    792     cinfo.scan_info = kScript;
    793     cinfo.num_scans = ARRAY_SIZE(kScript);
    794     jpegli_start_compress(&cinfo, TRUE);
    795     return true;
    796   };
    797   EXPECT_FALSE(try_catch_block());
    798   jpegli_destroy_compress(&cinfo);
    799   if (buffer) free(buffer);
    800 }
    801 
    802 TEST(EncoderErrorHandlingTest, InvalidScanScript12) {
    803   uint8_t* buffer = nullptr;
    804   unsigned long buffer_size = 0;
    805   jpeg_compress_struct cinfo;
    806   const auto try_catch_block = [&]() -> bool {
    807     ERROR_HANDLER_SETUP(jpegli);
    808     jpegli_create_compress(&cinfo);
    809     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    810     cinfo.image_width = 1;
    811     cinfo.image_height = 1;
    812     cinfo.input_components = 1;
    813     jpegli_set_defaults(&cinfo);
    814     static constexpr jpeg_scan_info kScript[] = {
    815         {1, {0}, 0, 0, 10, 1}, {1, {0}, 0, 0, 1, 0}, {1, {0}, 1, 63, 0, 0}  //
    816     };
    817     cinfo.scan_info = kScript;
    818     cinfo.num_scans = ARRAY_SIZE(kScript);
    819     jpegli_start_compress(&cinfo, TRUE);
    820     return true;
    821   };
    822   EXPECT_FALSE(try_catch_block());
    823   jpegli_destroy_compress(&cinfo);
    824   if (buffer) free(buffer);
    825 }
    826 
    827 TEST(EncoderErrorHandlingTest, InvalidScanScript13) {
    828   uint8_t* buffer = nullptr;
    829   unsigned long buffer_size = 0;
    830   jpeg_compress_struct cinfo;
    831   const auto try_catch_block = [&]() -> bool {
    832     ERROR_HANDLER_SETUP(jpegli);
    833     jpegli_create_compress(&cinfo);
    834     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    835     cinfo.image_width = 1;
    836     cinfo.image_height = 1;
    837     cinfo.input_components = 1;
    838     jpegli_set_defaults(&cinfo);
    839     static constexpr jpeg_scan_info kScript[] = {
    840         {1, {0}, 0, 0, 0, 2},
    841         {1, {0}, 0, 0, 1, 0},
    842         {1, {0}, 0, 0, 2, 1},  //
    843         {1, {0}, 1, 63, 0, 0}  //
    844     };
    845     cinfo.scan_info = kScript;
    846     cinfo.num_scans = ARRAY_SIZE(kScript);
    847     jpegli_start_compress(&cinfo, TRUE);
    848     return true;
    849   };
    850   EXPECT_FALSE(try_catch_block());
    851   jpegli_destroy_compress(&cinfo);
    852   if (buffer) free(buffer);
    853 }
    854 
    855 TEST(EncoderErrorHandlingTest, MCUSizeTooBig) {
    856   uint8_t* buffer = nullptr;
    857   unsigned long buffer_size = 0;
    858   jpeg_compress_struct cinfo;
    859   const auto try_catch_block = [&]() -> bool {
    860     ERROR_HANDLER_SETUP(jpegli);
    861     jpegli_create_compress(&cinfo);
    862     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    863     cinfo.image_width = 1;
    864     cinfo.image_height = 1;
    865     cinfo.input_components = 3;
    866     jpegli_set_defaults(&cinfo);
    867     jpegli_set_progressive_level(&cinfo, 0);
    868     cinfo.comp_info[0].h_samp_factor = 3;
    869     cinfo.comp_info[0].v_samp_factor = 3;
    870     jpegli_start_compress(&cinfo, TRUE);
    871     return true;
    872   };
    873   EXPECT_FALSE(try_catch_block());
    874   jpegli_destroy_compress(&cinfo);
    875   if (buffer) free(buffer);
    876 }
    877 
    878 TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) {
    879   uint8_t* buffer = nullptr;
    880   unsigned long buffer_size = 0;
    881   jpeg_compress_struct cinfo;
    882   const auto try_catch_block = [&]() -> bool {
    883     ERROR_HANDLER_SETUP(jpegli);
    884     jpegli_create_compress(&cinfo);
    885     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    886     cinfo.image_width = 1;
    887     cinfo.image_height = 1;
    888     cinfo.input_components = 1;
    889     jpegli_set_defaults(&cinfo);
    890     cinfo.restart_interval = 1000000;
    891     jpegli_start_compress(&cinfo, TRUE);
    892     return true;
    893   };
    894   EXPECT_FALSE(try_catch_block());
    895   jpegli_destroy_compress(&cinfo);
    896   if (buffer) free(buffer);
    897 }
    898 
    899 TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) {
    900   uint8_t* buffer = nullptr;
    901   unsigned long buffer_size = 0;
    902   jpeg_compress_struct cinfo;
    903   const auto try_catch_block = [&]() -> bool {
    904     ERROR_HANDLER_SETUP(jpegli);
    905     jpegli_create_compress(&cinfo);
    906     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    907     cinfo.image_width = 1;
    908     cinfo.image_height = 1;
    909     cinfo.input_components = 3;
    910     jpegli_set_defaults(&cinfo);
    911     cinfo.comp_info[0].h_samp_factor = 5;
    912     jpegli_start_compress(&cinfo, TRUE);
    913     return true;
    914   };
    915   EXPECT_FALSE(try_catch_block());
    916   jpegli_destroy_compress(&cinfo);
    917   if (buffer) free(buffer);
    918 }
    919 
    920 TEST(EncoderErrorHandlingTest, NonIntegralSamplingRatio) {
    921   uint8_t* buffer = nullptr;
    922   unsigned long buffer_size = 0;
    923   jpeg_compress_struct cinfo;
    924   const auto try_catch_block = [&]() -> bool {
    925     ERROR_HANDLER_SETUP(jpegli);
    926     jpegli_create_compress(&cinfo);
    927     jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
    928     cinfo.image_width = 1;
    929     cinfo.image_height = 1;
    930     cinfo.input_components = 3;
    931     jpegli_set_defaults(&cinfo);
    932     cinfo.comp_info[0].h_samp_factor = 3;
    933     cinfo.comp_info[1].h_samp_factor = 2;
    934     jpegli_start_compress(&cinfo, TRUE);
    935     return true;
    936   };
    937   EXPECT_FALSE(try_catch_block());
    938   jpegli_destroy_compress(&cinfo);
    939   if (buffer) free(buffer);
    940 }
    941 
    942 constexpr const char* kAddOnTable[] = {"First message",
    943                                        "Second message with int param %d",
    944                                        "Third message with string param %s"};
    945 
    946 TEST(EncoderErrorHandlingTest, AddOnTableNoParam) {
    947   jpeg_compress_struct cinfo;
    948   const auto try_catch_block = [&]() -> bool {
    949     ERROR_HANDLER_SETUP(jpegli);
    950     jpegli_create_compress(&cinfo);
    951     cinfo.err->addon_message_table = kAddOnTable;
    952     cinfo.err->first_addon_message = 10000;
    953     cinfo.err->last_addon_message = 10002;
    954     cinfo.err->msg_code = 10000;
    955     (*cinfo.err->error_exit)(reinterpret_cast<j_common_ptr>(&cinfo));
    956     return true;
    957   };
    958   EXPECT_FALSE(try_catch_block());
    959   jpegli_destroy_compress(&cinfo);
    960 }
    961 
    962 TEST(EncoderErrorHandlingTest, AddOnTableIntParam) {
    963   jpeg_compress_struct cinfo;
    964   const auto try_catch_block = [&]() -> bool {
    965     ERROR_HANDLER_SETUP(jpegli);
    966     jpegli_create_compress(&cinfo);
    967     cinfo.err->addon_message_table = kAddOnTable;
    968     cinfo.err->first_addon_message = 10000;
    969     cinfo.err->last_addon_message = 10002;
    970     cinfo.err->msg_code = 10001;
    971     cinfo.err->msg_parm.i[0] = 17;
    972     (*cinfo.err->error_exit)(reinterpret_cast<j_common_ptr>(&cinfo));
    973     return true;
    974   };
    975   EXPECT_FALSE(try_catch_block());
    976   jpegli_destroy_compress(&cinfo);
    977 }
    978 
    979 TEST(EncoderErrorHandlingTest, AddOnTableNoStringParam) {
    980   jpeg_compress_struct cinfo;
    981   const auto try_catch_block = [&]() -> bool {
    982     ERROR_HANDLER_SETUP(jpegli);
    983     jpegli_create_compress(&cinfo);
    984     cinfo.err->addon_message_table = kAddOnTable;
    985     cinfo.err->first_addon_message = 10000;
    986     cinfo.err->last_addon_message = 10002;
    987     cinfo.err->msg_code = 10002;
    988     memcpy(cinfo.err->msg_parm.s, "MESSAGE PARAM", 14);
    989     (*cinfo.err->error_exit)(reinterpret_cast<j_common_ptr>(&cinfo));
    990     return true;
    991   };
    992   EXPECT_FALSE(try_catch_block());
    993   jpegli_destroy_compress(&cinfo);
    994 }
    995 
    996 const uint8_t kCompressed0[] = {
    997     // SOI
    998     0xff, 0xd8,  //
    999     // DQT
   1000     0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02,  //
   1001     0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05,  //
   1002     0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0a, 0x07, 0x07, 0x06,  //
   1003     0x08, 0x0c, 0x0a, 0x0c, 0x0c, 0x0b, 0x0a, 0x0b, 0x0b, 0x0d,  //
   1004     0x0e, 0x12, 0x10, 0x0d, 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10,  //
   1005     0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0c, 0x0f,  //
   1006     0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14,        //
   1007     // SOF
   1008     0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01,  //
   1009     0x01, 0x11, 0x00,                                            //
   1010     // DHT
   1011     0xff, 0xc4, 0x00, 0xd2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,  //
   1012     0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //
   1013     0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,  //
   1014     0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,  //
   1015     0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,  //
   1016     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,  //
   1017     0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,  //
   1018     0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,  //
   1019     0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,  //
   1020     0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,  //
   1021     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,  //
   1022     0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,  //
   1023     0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,  //
   1024     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,  //
   1025     0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,  //
   1026     0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,  //
   1027     0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,  //
   1028     0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,  //
   1029     0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,  //
   1030     0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,  //
   1031     0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,  //
   1032     0xf9, 0xfa,                                                  //
   1033     // SOS
   1034     0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00,  //
   1035     // entropy coded data
   1036     0xfc, 0xaa, 0xaf,  //
   1037     // EOI
   1038     0xff, 0xd9,  //
   1039 };
   1040 const size_t kLen0 = sizeof(kCompressed0);
   1041 
   1042 const size_t kDQTOffset = 2;
   1043 const size_t kSOFOffset = 71;
   1044 const size_t kDHTOffset = 84;
   1045 const size_t kSOSOffset = 296;
   1046 
   1047 TEST(DecoderErrorHandlingTest, MinimalSuccess) {
   1048   JXL_CHECK(kCompressed0[kDQTOffset] == 0xff);
   1049   JXL_CHECK(kCompressed0[kSOFOffset] == 0xff);
   1050   JXL_CHECK(kCompressed0[kDHTOffset] == 0xff);
   1051   JXL_CHECK(kCompressed0[kSOSOffset] == 0xff);
   1052   jpeg_decompress_struct cinfo = {};
   1053   const auto try_catch_block = [&]() -> bool {
   1054     ERROR_HANDLER_SETUP(jpegli);
   1055     jpegli_create_decompress(&cinfo);
   1056     jpegli_mem_src(&cinfo, kCompressed0, kLen0);
   1057     jpegli_read_header(&cinfo, TRUE);
   1058     EXPECT_EQ(1, cinfo.image_width);
   1059     EXPECT_EQ(1, cinfo.image_height);
   1060     jpegli_start_decompress(&cinfo);
   1061     JSAMPLE image[1];
   1062     JSAMPROW row[] = {image};
   1063     jpegli_read_scanlines(&cinfo, row, 1);
   1064     EXPECT_EQ(0, image[0]);
   1065     jpegli_finish_decompress(&cinfo);
   1066     return true;
   1067   };
   1068   EXPECT_TRUE(try_catch_block());
   1069   jpegli_destroy_decompress(&cinfo);
   1070 }
   1071 
   1072 TEST(DecoderErrorHandlingTest, NoSource) {
   1073   jpeg_decompress_struct cinfo = {};
   1074   const auto try_catch_block = [&]() -> bool {
   1075     ERROR_HANDLER_SETUP(jpegli);
   1076     jpegli_create_decompress(&cinfo);
   1077     jpegli_read_header(&cinfo, TRUE);
   1078     return true;
   1079   };
   1080   EXPECT_FALSE(try_catch_block());
   1081   jpegli_destroy_decompress(&cinfo);
   1082 }
   1083 
   1084 TEST(DecoderErrorHandlingTest, NoReadHeader) {
   1085   jpeg_decompress_struct cinfo = {};
   1086   const auto try_catch_block = [&]() -> bool {
   1087     ERROR_HANDLER_SETUP(jpegli);
   1088     jpegli_create_decompress(&cinfo);
   1089     jpegli_mem_src(&cinfo, kCompressed0, kLen0);
   1090     jpegli_start_decompress(&cinfo);
   1091     return true;
   1092   };
   1093   EXPECT_FALSE(try_catch_block());
   1094   jpegli_destroy_decompress(&cinfo);
   1095 }
   1096 
   1097 TEST(DecoderErrorHandlingTest, NoStartDecompress) {
   1098   jpeg_decompress_struct cinfo = {};
   1099   const auto try_catch_block = [&]() -> bool {
   1100     ERROR_HANDLER_SETUP(jpegli);
   1101     jpegli_create_decompress(&cinfo);
   1102     jpegli_mem_src(&cinfo, kCompressed0, kLen0);
   1103     jpegli_read_header(&cinfo, TRUE);
   1104     EXPECT_EQ(1, cinfo.image_width);
   1105     EXPECT_EQ(1, cinfo.image_height);
   1106     JSAMPLE image[1];
   1107     JSAMPROW row[] = {image};
   1108     jpegli_read_scanlines(&cinfo, row, 1);
   1109     EXPECT_EQ(0, image[0]);
   1110     jpegli_finish_decompress(&cinfo);
   1111     return true;
   1112   };
   1113   EXPECT_FALSE(try_catch_block());
   1114   jpegli_destroy_decompress(&cinfo);
   1115 }
   1116 
   1117 TEST(DecoderErrorHandlingTest, NoReadScanlines) {
   1118   jpeg_decompress_struct cinfo = {};
   1119   const auto try_catch_block = [&]() -> bool {
   1120     ERROR_HANDLER_SETUP(jpegli);
   1121     jpegli_create_decompress(&cinfo);
   1122     jpegli_mem_src(&cinfo, kCompressed0, kLen0);
   1123     jpegli_read_header(&cinfo, TRUE);
   1124     EXPECT_EQ(1, cinfo.image_width);
   1125     EXPECT_EQ(1, cinfo.image_height);
   1126     jpegli_start_decompress(&cinfo);
   1127     jpegli_finish_decompress(&cinfo);
   1128     return true;
   1129   };
   1130   EXPECT_FALSE(try_catch_block());
   1131   jpegli_destroy_decompress(&cinfo);
   1132 }
   1133 
   1134 const size_t kMaxImageWidth = 0xffff;
   1135 JSAMPLE kOutputBuffer[MAX_COMPONENTS * kMaxImageWidth];
   1136 
   1137 bool ParseCompressed(const std::vector<uint8_t>& compressed) {
   1138   jpeg_decompress_struct cinfo = {};
   1139   const auto try_catch_block = [&]() -> bool {
   1140     ERROR_HANDLER_SETUP(jpegli);
   1141     jpegli_create_decompress(&cinfo);
   1142     jpegli_mem_src(&cinfo, compressed.data(), compressed.size());
   1143     jpegli_read_header(&cinfo, TRUE);
   1144     jpegli_start_decompress(&cinfo);
   1145     for (JDIMENSION i = 0; i < cinfo.output_height; ++i) {
   1146       JSAMPROW row[] = {kOutputBuffer};
   1147       jpegli_read_scanlines(&cinfo, row, 1);
   1148     }
   1149     jpegli_finish_decompress(&cinfo);
   1150     return true;
   1151   };
   1152   bool retval = try_catch_block();
   1153   jpegli_destroy_decompress(&cinfo);
   1154   return retval;
   1155 }
   1156 
   1157 TEST(DecoderErrorHandlingTest, NoSOI) {
   1158   for (int pos : {0, 1}) {
   1159     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1160     compressed[pos] = 0;
   1161     EXPECT_FALSE(ParseCompressed(compressed));
   1162   }
   1163 }
   1164 
   1165 TEST(DecoderErrorHandlingTest, InvalidDQT) {
   1166   // Bad marker length
   1167   for (int diff : {-2, -1, 1, 2}) {
   1168     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1169     compressed[kDQTOffset + 3] += diff;
   1170     EXPECT_FALSE(ParseCompressed(compressed));
   1171   }
   1172   // inavlid table index / precision
   1173   for (int val : {0x20, 0x05}) {
   1174     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1175     compressed[kDQTOffset + 4] = val;
   1176     EXPECT_FALSE(ParseCompressed(compressed));
   1177   }
   1178   // zero quant value
   1179   for (int k : {0, 1, 17, 63}) {
   1180     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1181     compressed[kDQTOffset + 5 + k] = 0;
   1182     EXPECT_FALSE(ParseCompressed(compressed));
   1183   }
   1184 }
   1185 
   1186 TEST(DecoderErrorHandlingTest, InvalidSOF) {
   1187   // Bad marker length
   1188   for (int diff : {-2, -1, 1, 2}) {
   1189     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1190     compressed[kSOFOffset + 3] += diff;
   1191     EXPECT_FALSE(ParseCompressed(compressed));
   1192   }
   1193   // zero width, height or num_components
   1194   for (int pos : {6, 8, 9}) {
   1195     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1196     compressed[kSOFOffset + pos] = 0;
   1197     EXPECT_FALSE(ParseCompressed(compressed));
   1198   }
   1199   // invalid data precision
   1200   for (int val : {0, 1, 127}) {
   1201     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1202     compressed[kSOFOffset + 4] = val;
   1203     EXPECT_FALSE(ParseCompressed(compressed));
   1204   }
   1205   // too many num_components
   1206   for (int val : {5, 255}) {
   1207     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1208     compressed[kSOFOffset + 9] = val;
   1209     EXPECT_FALSE(ParseCompressed(compressed));
   1210   }
   1211   // invalid sampling factors
   1212   for (int val : {0x00, 0x01, 0x10, 0x15, 0x51}) {
   1213     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1214     compressed[kSOFOffset + 11] = val;
   1215     EXPECT_FALSE(ParseCompressed(compressed));
   1216   }
   1217   // invalid quant table index
   1218   for (int val : {5, 17}) {
   1219     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1220     compressed[kSOFOffset + 12] = val;
   1221     EXPECT_FALSE(ParseCompressed(compressed));
   1222   }
   1223 }
   1224 
   1225 TEST(DecoderErrorHandlingTest, InvalidDHT) {
   1226   // Bad marker length
   1227   for (int diff : {-2, -1, 1, 2}) {
   1228     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1229     compressed[kDHTOffset + 3] += diff;
   1230     EXPECT_FALSE(ParseCompressed(compressed));
   1231   }
   1232   {
   1233     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1234     compressed[kDHTOffset + 2] += 17;
   1235     EXPECT_FALSE(ParseCompressed(compressed));
   1236   }
   1237   // inavlid table slot_id
   1238   for (int val : {0x05, 0x15, 0x20}) {
   1239     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1240     compressed[kDHTOffset + 4] = val;
   1241     EXPECT_FALSE(ParseCompressed(compressed));
   1242   }
   1243 }
   1244 
   1245 TEST(DecoderErrorHandlingTest, InvalidSOS) {
   1246   // Invalid comps_in_scan
   1247   for (int val : {2, 5, 17}) {
   1248     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1249     compressed[kSOSOffset + 4] = val;
   1250     EXPECT_FALSE(ParseCompressed(compressed));
   1251   }
   1252   // invalid Huffman table indexes
   1253   for (int val : {0x05, 0x50, 0x15, 0x51}) {
   1254     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1255     compressed[kSOSOffset + 6] = val;
   1256     EXPECT_FALSE(ParseCompressed(compressed));
   1257   }
   1258   // invalid Ss/Se
   1259   for (int pos : {7, 8}) {
   1260     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1261     compressed[kSOSOffset + pos] = 64;
   1262     EXPECT_FALSE(ParseCompressed(compressed));
   1263   }
   1264 }
   1265 
   1266 TEST(DecoderErrorHandlingTest, MutateSingleBytes) {
   1267   for (size_t pos = 0; pos < kLen0; ++pos) {
   1268     std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
   1269     for (int val : {0x00, 0x0f, 0xf0, 0xff}) {
   1270       compressed[pos] = val;
   1271       ParseCompressed(compressed);
   1272     }
   1273   }
   1274 }
   1275 
   1276 }  // namespace
   1277 }  // namespace jpegli