// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <vector>
#include "lib/jpegli/common.h"
#include "lib/jpegli/decode.h"
#include "lib/jpegli/encode.h"
#include "lib/jpegli/libjpeg_test_util.h"
#include "lib/jpegli/test_params.h"
#include "lib/jpegli/test_utils.h"
#include "lib/jpegli/testing.h"
namespace jpegli {
namespace {
TEST(EncoderErrorHandlingTest, MinimalSuccess) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
{
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_TRUE(try_catch_block());
jpegli_destroy_compress(&cinfo);
}
TestImage output;
DecodeWithLibjpeg(CompressParams(), DecompressParams(), nullptr, 0 , buffer,
buffer_size, &output);
EXPECT_EQ(1 , output.xsize);
EXPECT_EQ(1 , output.ysize);
EXPECT_EQ(1 , output.components);
EXPECT_EQ(0 , output.pixels[0 ]);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NoDestination) {
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
}
TEST(EncoderErrorHandlingTest, NoImageDimensions) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, ImageTooBig) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 100000 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NoInputComponents) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, TooManyInputComponents) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1000 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NoSetDefaults) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NoStartCompress) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NoWriteScanlines) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 2 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidQuantValue) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
cinfo.quant_tbl_ptrs[0 ] =
jpegli_alloc_quant_table(reinterpret_cast <j_common_ptr>(&cinfo));
for (UINT16& q : cinfo.quant_tbl_ptrs[0 ]->quantval) {
q = 0 ;
}
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
cinfo.comp_info[0 ].quant_tbl_no = 3 ;
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
cinfo.num_components = 100 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
cinfo.num_components = 2 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
cinfo.num_components = 2 ;
cinfo.comp_info[1 ].h_samp_factor = cinfo.comp_info[1 ].v_samp_factor = 1 ;
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
cinfo.in_color_space = JCS_RGB;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[1 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
cinfo.in_color_space = JCS_GRAYSCALE;
jpegli_set_defaults(&cinfo);
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[3 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
cinfo.in_color_space = JCS_RGB;
jpegli_set_defaults(&cinfo);
cinfo.num_components = 2 ;
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[3 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidColorTransform) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
cinfo.in_color_space = JCS_YCbCr;
jpegli_set_defaults(&cinfo);
cinfo.jpeg_color_space = JCS_RGB;
jpegli_start_compress(&cinfo, TRUE );
JSAMPLE image[3 ] = {0 };
JSAMPROW row[] = {image};
jpegli_write_scanlines(&cinfo, row, 1 );
jpegli_finish_compress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, DuplicateComponentIds) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
cinfo.comp_info[0 ].component_id = 0 ;
cinfo.comp_info[1 ].component_id = 0 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidComponentIndex) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
cinfo.comp_info[0 ].component_index = 17 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, ArithmeticCoding) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
cinfo.arith_code = TRUE ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, CCIR601Sampling) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
cinfo.CCIR601_sampling = TRUE ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript1) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{1 , {0 }, 0 , 63 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = 0 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript2) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{2 , {0 , 1 }, 0 , 63 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript3) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{5 , {0 }, 0 , 63 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript4) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 2 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{2 , {0 , 0 }, 0 , 63 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript5) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 2 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{2 , {1 , 0 }, 0 , 63 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript6) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{1 , {0 }, 0 , 64 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript7) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {{1 , {0 }, 2 , 1 , 0 , 0 }}; //
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript8) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 2 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {
{1 , {0 }, 0 , 63 , 0 , 0 }, {1 , {1 }, 0 , 0 , 0 , 0 }, {1 , {1 }, 1 , 63 , 0 , 0 } //
};
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript9) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {
{1 , {0 }, 0 , 1 , 0 , 0 }, {1 , {0 }, 2 , 63 , 0 , 0 }, //
};
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript10) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 2 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {
{2 , {0 , 1 }, 0 , 0 , 0 , 0 }, {2 , {0 , 1 }, 1 , 63 , 0 , 0 } //
};
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript11) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {
{1 , {0 }, 1 , 63 , 0 , 0 }, {1 , {0 }, 0 , 0 , 0 , 0 } //
};
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript12) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {
{1 , {0 }, 0 , 0 , 10 , 1 }, {1 , {0 }, 0 , 0 , 1 , 0 }, {1 , {0 }, 1 , 63 , 0 , 0 } //
};
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, InvalidScanScript13) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
static constexpr jpeg_scan_info kScript[] = {
{1 , {0 }, 0 , 0 , 0 , 2 },
{1 , {0 }, 0 , 0 , 1 , 0 },
{1 , {0 }, 0 , 0 , 2 , 1 }, //
{1 , {0 }, 1 , 63 , 0 , 0 } //
};
cinfo.scan_info = kScript;
cinfo.num_scans = ARRAY_SIZE(kScript);
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, MCUSizeTooBig) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
jpegli_set_progressive_level(&cinfo, 0 );
cinfo.comp_info[0 ].h_samp_factor = 3 ;
cinfo.comp_info[0 ].v_samp_factor = 3 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 1 ;
jpegli_set_defaults(&cinfo);
cinfo.restart_interval = 1000000 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
cinfo.comp_info[0 ].h_samp_factor = 5 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
TEST(EncoderErrorHandlingTest, NonIntegralSamplingRatio) {
uint8_t* buffer = nullptr;
unsigned long buffer_size = 0 ; // NOLINT
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
jpegli_mem_dest(&cinfo, &buffer, &buffer_size);
cinfo.image_width = 1 ;
cinfo.image_height = 1 ;
cinfo.input_components = 3 ;
jpegli_set_defaults(&cinfo);
cinfo.comp_info[0 ].h_samp_factor = 3 ;
cinfo.comp_info[1 ].h_samp_factor = 2 ;
jpegli_start_compress(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
if (buffer) free(buffer);
}
constexpr const char * kAddOnTable[] = {"First message" ,
"Second message with int param %d" ,
"Third message with string param %s" };
TEST(EncoderErrorHandlingTest, AddOnTableNoParam) {
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
cinfo.err->addon_message_table = kAddOnTable;
cinfo.err->first_addon_message = 10000 ;
cinfo.err->last_addon_message = 10002 ;
cinfo.err->msg_code = 10000 ;
(*cinfo.err->error_exit)(reinterpret_cast <j_common_ptr>(&cinfo));
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
}
TEST(EncoderErrorHandlingTest, AddOnTableIntParam) {
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
cinfo.err->addon_message_table = kAddOnTable;
cinfo.err->first_addon_message = 10000 ;
cinfo.err->last_addon_message = 10002 ;
cinfo.err->msg_code = 10001 ;
cinfo.err->msg_parm.i[0 ] = 17 ;
(*cinfo.err->error_exit)(reinterpret_cast <j_common_ptr>(&cinfo));
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
}
TEST(EncoderErrorHandlingTest, AddOnTableNoStringParam) {
jpeg_compress_struct cinfo;
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_compress(&cinfo);
cinfo.err->addon_message_table = kAddOnTable;
cinfo.err->first_addon_message = 10000 ;
cinfo.err->last_addon_message = 10002 ;
cinfo.err->msg_code = 10002 ;
memcpy(cinfo.err->msg_parm.s, "MESSAGE PARAM" , 14 );
(*cinfo.err->error_exit)(reinterpret_cast <j_common_ptr>(&cinfo));
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_compress(&cinfo);
}
const uint8_t kCompressed0[] = {
// SOI
0 xff, 0 xd8, //
// SOF
0 xff, 0 xc0, 0 x00, 0 x0b, 0 x08, 0 x00, 0 x01, 0 x00, 0 x01, 0 x01, //
0 x01, 0 x11, 0 x00, //
// DQT
0 xff, 0 xdb, 0 x00, 0 x43, 0 x00, 0 x03, 0 x02, 0 x02, 0 x03, 0 x02, //
0 x02, 0 x03, 0 x03, 0 x03, 0 x03, 0 x04, 0 x03, 0 x03, 0 x04, 0 x05, //
0 x08, 0 x05, 0 x05, 0 x04, 0 x04, 0 x05, 0 x0a, 0 x07, 0 x07, 0 x06, //
0 x08, 0 x0c, 0 x0a, 0 x0c, 0 x0c, 0 x0b, 0 x0a, 0 x0b, 0 x0b, 0 x0d, //
0 x0e, 0 x12, 0 x10, 0 x0d, 0 x0e, 0 x11, 0 x0e, 0 x0b, 0 x0b, 0 x10, //
0 x16, 0 x10, 0 x11, 0 x13, 0 x14, 0 x15, 0 x15, 0 x15, 0 x0c, 0 x0f, //
0 x17, 0 x18, 0 x16, 0 x14, 0 x18, 0 x12, 0 x14, 0 x15, 0 x14, //
// DHT
0 xff, 0 xc4, 0 x00, 0 xd2, 0 x00, 0 x00, 0 x01, 0 x05, 0 x01, 0 x01, //
0 x01, 0 x01, 0 x01, 0 x01, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, //
0 x00, 0 x00, 0 x01, 0 x02, 0 x03, 0 x04, 0 x05, 0 x06, 0 x07, 0 x08, //
0 x09, 0 x0a, 0 x0b, 0 x10, 0 x00, 0 x02, 0 x01, 0 x03, 0 x03, 0 x02, //
0 x04, 0 x03, 0 x05, 0 x05, 0 x04, 0 x04, 0 x00, 0 x00, 0 x01, 0 x7d, //
0 x01, 0 x02, 0 x03, 0 x00, 0 x04, 0 x11, 0 x05, 0 x12, 0 x21, 0 x31, //
0 x41, 0 x06, 0 x13, 0 x51, 0 x61, 0 x07, 0 x22, 0 x71, 0 x14, 0 x32, //
0 x81, 0 x91, 0 xa1, 0 x08, 0 x23, 0 x42, 0 xb1, 0 xc1, 0 x15, 0 x52, //
0 xd1, 0 xf0, 0 x24, 0 x33, 0 x62, 0 x72, 0 x82, 0 x09, 0 x0a, 0 x16, //
0 x17, 0 x18, 0 x19, 0 x1a, 0 x25, 0 x26, 0 x27, 0 x28, 0 x29, 0 x2a, //
0 x34, 0 x35, 0 x36, 0 x37, 0 x38, 0 x39, 0 x3a, 0 x43, 0 x44, 0 x45, //
0 x46, 0 x47, 0 x48, 0 x49, 0 x4a, 0 x53, 0 x54, 0 x55, 0 x56, 0 x57, //
0 x58, 0 x59, 0 x5a, 0 x63, 0 x64, 0 x65, 0 x66, 0 x67, 0 x68, 0 x69, //
0 x6a, 0 x73, 0 x74, 0 x75, 0 x76, 0 x77, 0 x78, 0 x79, 0 x7a, 0 x83, //
0 x84, 0 x85, 0 x86, 0 x87, 0 x88, 0 x89, 0 x8a, 0 x92, 0 x93, 0 x94, //
0 x95, 0 x96, 0 x97, 0 x98, 0 x99, 0 x9a, 0 xa2, 0 xa3, 0 xa4, 0 xa5, //
0 xa6, 0 xa7, 0 xa8, 0 xa9, 0 xaa, 0 xb2, 0 xb3, 0 xb4, 0 xb5, 0 xb6, //
0 xb7, 0 xb8, 0 xb9, 0 xba, 0 xc2, 0 xc3, 0 xc4, 0 xc5, 0 xc6, 0 xc7, //
0 xc8, 0 xc9, 0 xca, 0 xd2, 0 xd3, 0 xd4, 0 xd5, 0 xd6, 0 xd7, 0 xd8, //
0 xd9, 0 xda, 0 xe1, 0 xe2, 0 xe3, 0 xe4, 0 xe5, 0 xe6, 0 xe7, 0 xe8, //
0 xe9, 0 xea, 0 xf1, 0 xf2, 0 xf3, 0 xf4, 0 xf5, 0 xf6, 0 xf7, 0 xf8, //
0 xf9, 0 xfa, //
// SOS
0 xff, 0 xda, 0 x00, 0 x08, 0 x01, 0 x01, 0 x00, 0 x00, 0 x3f, 0 x00, //
// entropy coded data
0 xfc, 0 xaa, 0 xaf, //
// EOI
0 xff, 0 xd9, //
};
const size_t kLen0 = sizeof (kCompressed0);
const size_t kSOFOffset = 2 ;
const size_t kDQTOffset = 15 ;
const size_t kDHTOffset = 84 ;
const size_t kSOSOffset = 296 ;
TEST(DecoderErrorHandlingTest, MinimalSuccess) {
ASSERT_TRUE(kCompressed0[kDQTOffset] == 0 xff);
ASSERT_TRUE(kCompressed0[kSOFOffset] == 0 xff);
ASSERT_TRUE(kCompressed0[kDHTOffset] == 0 xff);
ASSERT_TRUE(kCompressed0[kSOSOffset] == 0 xff);
jpeg_decompress_struct cinfo = {};
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_decompress(&cinfo);
jpegli_mem_src(&cinfo, kCompressed0, kLen0);
jpegli_read_header(&cinfo, TRUE );
EXPECT_EQ(1 , cinfo.image_width);
EXPECT_EQ(1 , cinfo.image_height);
jpegli_start_decompress(&cinfo);
JSAMPLE image[1 ];
JSAMPROW row[] = {image};
jpegli_read_scanlines(&cinfo, row, 1 );
EXPECT_EQ(0 , image[0 ]);
jpegli_finish_decompress(&cinfo);
return true ;
};
EXPECT_TRUE(try_catch_block());
jpegli_destroy_decompress(&cinfo);
}
TEST(DecoderErrorHandlingTest, NoSource) {
jpeg_decompress_struct cinfo = {};
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_decompress(&cinfo);
jpegli_read_header(&cinfo, TRUE );
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_decompress(&cinfo);
}
TEST(DecoderErrorHandlingTest, NoReadHeader) {
jpeg_decompress_struct cinfo = {};
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_decompress(&cinfo);
jpegli_mem_src(&cinfo, kCompressed0, kLen0);
jpegli_start_decompress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_decompress(&cinfo);
}
TEST(DecoderErrorHandlingTest, NoStartDecompress) {
jpeg_decompress_struct cinfo = {};
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_decompress(&cinfo);
jpegli_mem_src(&cinfo, kCompressed0, kLen0);
jpegli_read_header(&cinfo, TRUE );
EXPECT_EQ(1 , cinfo.image_width);
EXPECT_EQ(1 , cinfo.image_height);
JSAMPLE image[1 ];
JSAMPROW row[] = {image};
jpegli_read_scanlines(&cinfo, row, 1 );
EXPECT_EQ(0 , image[0 ]);
jpegli_finish_decompress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_decompress(&cinfo);
}
TEST(DecoderErrorHandlingTest, NoReadScanlines) {
jpeg_decompress_struct cinfo = {};
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_decompress(&cinfo);
jpegli_mem_src(&cinfo, kCompressed0, kLen0);
jpegli_read_header(&cinfo, TRUE );
EXPECT_EQ(1 , cinfo.image_width);
EXPECT_EQ(1 , cinfo.image_height);
jpegli_start_decompress(&cinfo);
jpegli_finish_decompress(&cinfo);
return true ;
};
EXPECT_FALSE(try_catch_block());
jpegli_destroy_decompress(&cinfo);
}
const size_t kMaxImageWidth = 0 xffff;
JSAMPLE kOutputBuffer[MAX_COMPONENTS * kMaxImageWidth];
bool ParseCompressed(const std::vector<uint8_t>& compressed) {
jpeg_decompress_struct cinfo = {};
const auto try_catch_block = [&]() -> bool {
ERROR_HANDLER_SETUP(jpegli);
jpegli_create_decompress(&cinfo);
jpegli_mem_src(&cinfo, compressed.data(), compressed.size());
jpegli_read_header(&cinfo, TRUE );
jpegli_start_decompress(&cinfo);
for (JDIMENSION i = 0 ; i < cinfo.output_height; ++i) {
JSAMPROW row[] = {kOutputBuffer};
jpegli_read_scanlines(&cinfo, row, 1 );
}
jpegli_finish_decompress(&cinfo);
return true ;
};
bool retval = try_catch_block();
jpegli_destroy_decompress(&cinfo);
return retval;
}
TEST(DecoderErrorHandlingTest, NoSOI) {
for (int pos : {0 , 1 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[pos] = 0 ;
EXPECT_FALSE(ParseCompressed(compressed));
}
}
TEST(DecoderErrorHandlingTest, InvalidDQT) {
// Bad marker length
for (int diff : {-2 , -1 , 1 , 2 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kDQTOffset + 3 ] += diff;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid table index / precision
for (int val : {0 x20, 0 x05}) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kDQTOffset + 4 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
// zero quant value
for (int k : {0 , 1 , 17 , 63 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kDQTOffset + 5 + k] = 0 ;
EXPECT_FALSE(ParseCompressed(compressed));
}
}
TEST(DecoderErrorHandlingTest, InvalidSOF) {
// Bad marker length
for (int diff : {-2 , -1 , 1 , 2 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOFOffset + 3 ] += diff;
EXPECT_FALSE(ParseCompressed(compressed));
}
// zero width, height or num_components
for (int pos : {6 , 8 , 9 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOFOffset + pos] = 0 ;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid data precision
for (int val : {0 , 1 , 127 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOFOffset + 4 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
// too many num_components
for (int val : {5 , 255 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOFOffset + 9 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid sampling factors
for (int val : {0 x00, 0 x01, 0 x10, 0 x15, 0 x51}) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOFOffset + 11 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid quant table index
for (int val : {5 , 17 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOFOffset + 12 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
}
TEST(DecoderErrorHandlingTest, InvalidDHT) {
// Bad marker length
for (int diff : {-2 , -1 , 1 , 2 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kDHTOffset + 3 ] += diff;
EXPECT_FALSE(ParseCompressed(compressed));
}
{
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kDHTOffset + 2 ] += 17 ;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid table slot_id
for (int val : {0 x05, 0 x15, 0 x20}) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kDHTOffset + 4 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
}
TEST(DecoderErrorHandlingTest, InvalidSOS) {
// Invalid comps_in_scan
for (int val : {2 , 5 , 17 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOSOffset + 4 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid Huffman table indexes
for (int val : {0 x05, 0 x50, 0 x15, 0 x51}) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOSOffset + 6 ] = val;
EXPECT_FALSE(ParseCompressed(compressed));
}
// invalid Ss/Se
for (int pos : {7 , 8 }) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
compressed[kSOSOffset + pos] = 64 ;
EXPECT_FALSE(ParseCompressed(compressed));
}
}
TEST(DecoderErrorHandlingTest, MutateSingleBytes) {
for (size_t pos = 0 ; pos < kLen0; ++pos) {
std::vector<uint8_t> compressed(kCompressed0, kCompressed0 + kLen0);
for (int val : {0 x00, 0 x0f, 0 xf0, 0 xff}) {
compressed[pos] = val;
ParseCompressed(compressed);
}
}
}
} // namespace
} // namespace jpegli
Messung V0.5 in Prozent C=85 H=97 G=91
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-05)
¤
*© Formatika GbR, Deutschland