Validate interleave mode against component count (#119)

If component count is 1 then only interleave mode none may be used.
Validate this during encoding and decoding.
This commit is contained in:
Victor Derks 2021-12-20 20:34:00 +01:00 committed by GitHub
parent e90cba4817
commit 04b08b7718
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 69 additions and 10 deletions

View File

@ -333,9 +333,9 @@ public:
/// This will be returned as a callback_failed error code.
/// </remarks>
/// <param name="comment_handler">Function object to the comment handler.</param>
jpegls_decoder& at_comment(const std::function<void(const void* data, size_t size)> comment_handler)
jpegls_decoder& at_comment(std::function<void(const void* data, size_t size)> comment_handler)
{
comment_handler_ = comment_handler;
comment_handler_ = std::move(comment_handler);
check_jpegls_errc(
charls_jpegls_decoder_at_comment(decoder_.get(), comment_handler_ ? at_comment_callback : nullptr, this));
return *this;

View File

@ -108,7 +108,7 @@ static void* bmp_read_pixel_data(FILE* fp, const uint32_t offset, const bmp_dib_
}
static void* handle_encoder_failure(const charls_jpegls_errc error, const char* step, charls_jpegls_encoder* encoder,
static void* handle_encoder_failure(const charls_jpegls_errc error, const char* step, const charls_jpegls_encoder* encoder,
void* buffer)
{
printf("Failed to %s: %i, %s\n", step, error, charls_get_error_message(error));

View File

@ -222,7 +222,7 @@ int main(const int argc, char** argv)
convert_bgr_to_rgb(bmp_image.pixel_data, bmp_image.dib_header.width,
static_cast<size_t>(bmp_image.dib_header.height), bmp_image.stride);
auto encoded_buffer{encode_bmp_image_to_jpegls(bmp_image, options.interleave_mode, options.near_lossless)};
const auto encoded_buffer{encode_bmp_image_to_jpegls(bmp_image, options.interleave_mode, options.near_lossless)};
save_buffer_to_file(encoded_buffer.data(), encoded_buffer.size(), options.output_filename);
return EXIT_SUCCESS;

View File

@ -39,9 +39,7 @@ struct charls_jpegls_encoder final
void interleave_mode(const charls::interleave_mode interleave_mode)
{
check_argument(interleave_mode >= charls::interleave_mode::none &&
interleave_mode <= charls::interleave_mode::sample,
jpegls_errc::invalid_argument_interleave_mode);
check_interleave_mode(interleave_mode, jpegls_errc::invalid_argument_interleave_mode);
interleave_mode_ = interleave_mode;
}
@ -122,6 +120,7 @@ struct charls_jpegls_encoder final
{
check_argument(source.data || source.size == 0);
check_operation(is_frame_info_configured() && state_ != state::initial);
check_interleave_mode_against_component_count();
if (!is_valid(preset_coding_parameters_, calculate_maximum_sample_value(frame_info_.bits_per_sample), near_lossless_,
&validated_pc_parameters_))
@ -249,6 +248,12 @@ private:
}
}
void check_interleave_mode_against_component_count() const
{
if (frame_info_.component_count == 1 && interleave_mode_ != interleave_mode::none)
throw_jpegls_error(jpegls_errc::invalid_argument_interleave_mode);
}
void transition_to_tables_and_miscellaneous_state()
{
if (state_ == state::tables_and_miscellaneous)

View File

@ -499,8 +499,7 @@ void jpeg_stream_reader::read_start_of_scan()
throw_jpegls_error(jpegls_errc::invalid_parameter_near_lossless);
const auto mode{static_cast<interleave_mode>(read_byte())}; // Read ILV parameter
if (!(mode == interleave_mode::none || mode == interleave_mode::line || mode == interleave_mode::sample))
throw_jpegls_error(jpegls_errc::invalid_parameter_interleave_mode);
check_interleave_mode(mode);
parameters_.interleave_mode = mode;
if ((read_byte() & 0xFU) != 0) // Read Ah (no meaning) and Al (point transform).
@ -677,6 +676,15 @@ void jpeg_stream_reader::check_parameter_coherent() const
}
void jpeg_stream_reader::check_interleave_mode(const interleave_mode mode) const
{
constexpr auto errc{jpegls_errc::invalid_parameter_interleave_mode};
charls::check_interleave_mode(mode, errc);
if (frame_info_.component_count == 1 && mode != interleave_mode::none)
throw_jpegls_error(errc);
}
uint32_t jpeg_stream_reader::maximum_sample_value() const noexcept
{
if (preset_coding_parameters_.maximum_sample_value != 0)

View File

@ -90,6 +90,7 @@ private:
int try_read_hp_color_transform_segment();
void add_component(uint8_t component_id);
void check_parameter_coherent() const;
void check_interleave_mode(interleave_mode mode) const;
uint32_t maximum_sample_value() const noexcept;
enum class state

View File

@ -331,6 +331,13 @@ inline void check_argument(const bool expression, const jpegls_errc error_value
}
inline void check_interleave_mode(const charls::interleave_mode mode, const jpegls_errc error_value)
{
if (!(mode == interleave_mode::none || mode == interleave_mode::line || mode == interleave_mode::sample))
impl::throw_jpegls_error(error_value);
}
CONSTEXPR int32_t calculate_maximum_sample_value(const int32_t bits_per_sample)
{
ASSERT(bits_per_sample > 0 && bits_per_sample <= 16);

View File

@ -438,6 +438,16 @@ public:
assert_expect_exception(jpegls_errc::invalid_parameter_near_lossless, [&reader] { reader.read_start_of_scan(); });
}
TEST_METHOD(read_header_line_interleave_in_sos_for_single_component_should_throw) // NOLINT
{
read_header_incorrect_interleave_in_sos_for_single_component_should_throw(interleave_mode::line);
}
TEST_METHOD(read_header_sample_interleave_in_sos_for_single_component_should_throw) // NOLINT
{
read_header_incorrect_interleave_in_sos_for_single_component_should_throw(interleave_mode::sample);
}
TEST_METHOD(read_header_with_duplicate_component_id_in_start_of_frame_segment_should_throw) // NOLINT
{
jpeg_test_stream_writer writer;
@ -849,6 +859,20 @@ private:
reader.read_header(); // if it doesn't throw test is passed.
}
static void read_header_incorrect_interleave_in_sos_for_single_component_should_throw(const interleave_mode mode)
{
jpeg_test_stream_writer writer;
writer.write_start_of_image();
writer.write_start_of_frame_segment(512, 512, 8, 1);
writer.write_start_of_scan_segment(0, 1, 0, mode);
jpeg_stream_reader reader;
reader.source({writer.buffer.data(), writer.buffer.size()});
reader.read_header();
assert_expect_exception(jpegls_errc::invalid_parameter_interleave_mode, [&reader] { reader.read_start_of_scan(); });
}
};
}} // namespace charls::test

View File

@ -113,6 +113,19 @@ public:
[&encoder] { encoder.interleave_mode(static_cast<charls::interleave_mode>(3)); });
}
TEST_METHOD(interleave_mode_does_not_match_component_count) // NOLINT
{
constexpr frame_info frame_info{512, 512, 8, 1};
vector<uint8_t> source(static_cast<size_t>(frame_info.width) * frame_info.height);
assert_expect_exception(jpegls_errc::invalid_argument_interleave_mode, [&frame_info, &source] {
jpegls_encoder::encode(source, frame_info, interleave_mode::sample);
});
assert_expect_exception(jpegls_errc::invalid_argument_interleave_mode, [&frame_info, &source] {
jpegls_encoder::encode(source, frame_info, interleave_mode::line);
});
}
TEST_METHOD(near_lossless) // NOLINT
{
jpegls_encoder encoder;
@ -598,7 +611,8 @@ public:
encoder.frame_info({3, 1, 16, 1});
ignore = encoder.encode(source);
assert_expect_exception(jpegls_errc::invalid_operation, [&encoder] { ignore = encoder.write_comment("after-encoding"); });
assert_expect_exception(jpegls_errc::invalid_operation,
[&encoder] { ignore = encoder.write_comment("after-encoding"); });
}
TEST_METHOD(write_comment_before_encode) // NOLINT