From cf386182346fc267306032deb757b6c0a4416f8c Mon Sep 17 00:00:00 2001 From: Chris Hafey Date: Tue, 19 May 2020 17:35:17 +0000 Subject: [PATCH 01/12] added support for partial bitstream decoding --- src/lib/openjp2/j2k.c | 2 +- src/lib/openjp2/t2.c | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 6cb6b8caa..3a4cada0a 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -4966,7 +4966,7 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k, opj_stream_get_number_byte_left(p_stream)) { opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n"); - return OPJ_FALSE; + //return OPJ_FALSE; } if (p_j2k->m_specific_param.m_decoder.m_sot_length > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA) { diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 066038926..3e6d08164 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -502,7 +502,6 @@ OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd, l_current_pi->precno, l_current_pi->layno, skip_packet ? "skipped" : "kept"); */ } - if (!skip_packet) { l_nb_bytes_read = 0; @@ -1378,6 +1377,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, opj_tcd_cblk_dec_t* l_cblk = 00; opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + OPJ_UINT32 partial_buffer = 0; OPJ_ARG_NOT_USED(p_t2); OPJ_ARG_NOT_USED(pack_info); @@ -1397,6 +1397,12 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { opj_tcd_seg_t *l_seg = 00; + // if we have a partial data stream, set numchunks to zero + // since we have no data to actually decode. + if(partial_buffer) { + l_cblk->numchunks = 0; + } + if (!l_cblk->numnewpasses) { /* nothing to do */ ++l_cblk; @@ -1419,12 +1425,29 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, /* Check possible overflow (on l_current_data only, assumes input args already checked) then size */ if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) < (OPJ_SIZE_T)l_current_data) || - (l_current_data + l_seg->newlen > p_src_data + p_max_length)) { + (l_current_data + l_seg->newlen > p_src_data + p_max_length) || + (partial_buffer)) { opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); - return OPJ_FALSE; + // NOTE - originall we would return OPJ_FALSE here when we encountered partial bitstream + //return OPJ_FALSE; + + // skip this codeblock since it is a partial read + partial_buffer = 1; + l_cblk->numchunks = 0; + + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + if (l_cblk->numnewpasses > 0) { + ++l_seg; + ++l_cblk->numsegs; + } + if(l_cblk->numnewpasses > 0) { + break; + } + continue; } #ifdef USE_JPWL @@ -1486,8 +1509,12 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, ++l_band; } - *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); - + // return the number of bytes read + if(partial_buffer) { + *(p_data_read) = p_max_length; + } else { + *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); + } return OPJ_TRUE; } From 6abcd9b7aa5de273c37b5d49db9c49f0093c7a01 Mon Sep 17 00:00:00 2001 From: Chris Hafey Date: Tue, 19 May 2020 19:50:36 +0000 Subject: [PATCH 02/12] fixed bug where packet skipping wasn't working with partial bitstream --- src/lib/openjp2/t2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 3e6d08164..37d7e950f 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -1580,7 +1580,7 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2, "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); - return OPJ_FALSE; + //return OPJ_FALSE; } #ifdef USE_JPWL From 86d27d7060f2c4d93cd4a195fe6e2042456ca0d6 Mon Sep 17 00:00:00 2001 From: Chris Hafey Date: Wed, 20 May 2020 19:09:15 +0000 Subject: [PATCH 03/12] changed ERROR->WARNING for log messages --- src/lib/openjp2/j2k.c | 3 +-- src/lib/openjp2/t2.c | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 3a4cada0a..31a1cff7e 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -4964,9 +4964,8 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k, /* Check enough bytes left in stream before allocation */ if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) { - opj_event_msg(p_manager, EVT_ERROR, + opj_event_msg(p_manager, EVT_WARNING, "Tile part length size inconsistent with stream length\n"); - //return OPJ_FALSE; } if (p_j2k->m_specific_param.m_decoder.m_sot_length > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA) { diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 37d7e950f..e43f3fa98 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -1427,13 +1427,10 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, (OPJ_SIZE_T)l_current_data) || (l_current_data + l_seg->newlen > p_src_data + p_max_length) || (partial_buffer)) { - opj_event_msg(p_manager, EVT_ERROR, + opj_event_msg(p_manager, EVT_WARNING, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); - // NOTE - originall we would return OPJ_FALSE here when we encountered partial bitstream - //return OPJ_FALSE; - // skip this codeblock since it is a partial read partial_buffer = 1; l_cblk->numchunks = 0; From c329491ca4bc3b28f8ce9a5f12ea806e2c444b88 Mon Sep 17 00:00:00 2001 From: Chris Hafey Date: Sat, 9 Oct 2021 10:11:55 -0500 Subject: [PATCH 04/12] Added opj_decoder_set_strict_mode() to control whether or not partial decoding is enabled --- src/lib/openjp2/j2k.c | 18 +++++++++-- src/lib/openjp2/j2k.h | 4 +++ src/lib/openjp2/jp2.c | 5 +++ src/lib/openjp2/jp2.h | 9 ++++++ src/lib/openjp2/openjpeg.c | 27 ++++++++++++++++ src/lib/openjp2/openjpeg.h | 13 ++++++++ src/lib/openjp2/opj_codec.h | 3 ++ src/lib/openjp2/t2.c | 61 +++++++++++++++++++++++-------------- 8 files changed, 115 insertions(+), 25 deletions(-) diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 31a1cff7e..16dd1c318 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -4964,8 +4964,14 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k, /* Check enough bytes left in stream before allocation */ if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) { - opj_event_msg(p_manager, EVT_WARNING, - "Tile part length size inconsistent with stream length\n"); + if(p_j2k->m_cp.strict) { + opj_event_msg(p_manager, EVT_ERROR, + "Tile part length size inconsistent with stream length\n"); + return OPJ_FALSE; + } else { + opj_event_msg(p_manager, EVT_WARNING, + "Tile part length size inconsistent with stream length\n"); + } } if (p_j2k->m_specific_param.m_decoder.m_sot_length > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA) { @@ -6684,6 +6690,7 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) if (j2k && parameters) { j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer; j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce; + j2k->m_cp.strict = OPJ_TRUE; j2k->dump_state = (parameters->flags & OPJ_DPARAMETERS_DUMP_FLAG); #ifdef USE_JPWL @@ -6694,6 +6701,13 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) } } +void opj_j2k_decoder_set_strict_mode(opj_j2k_t *j2k, OPJ_BOOL strict) +{ + if (j2k) { + j2k->m_cp.strict = strict; + } +} + OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads) { /* Currently we pass the thread-pool to the tcd, so we cannot re-set it */ diff --git a/src/lib/openjp2/j2k.h b/src/lib/openjp2/j2k.h index fc17166e0..04fba645a 100644 --- a/src/lib/openjp2/j2k.h +++ b/src/lib/openjp2/j2k.h @@ -402,6 +402,8 @@ typedef struct opj_cp { } m_specific_param; + /** OPJ_TRUE if entire bit stream must be decoded, OPJ_FALSE if partial bitstream decoding allowed */ + OPJ_BOOL strict; /* UniPG>> */ #ifdef USE_JPWL @@ -625,6 +627,8 @@ Decoding parameters are returned in j2k->cp. */ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters); +void opj_j2k_decoder_set_strict_mode(opj_j2k_t *j2k, OPJ_BOOL strict); + OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads); /** diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index 449440b8c..17572195e 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -1901,6 +1901,11 @@ void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; } +void opj_jp2_decoder_set_strict_mode(opj_jp2_t *jp2, OPJ_BOOL strict) +{ + opj_j2k_decoder_set_strict_mode(jp2->j2k, strict); +} + OPJ_BOOL opj_jp2_set_threads(opj_jp2_t *jp2, OPJ_UINT32 num_threads) { return opj_j2k_set_threads(jp2->j2k, num_threads); diff --git a/src/lib/openjp2/jp2.h b/src/lib/openjp2/jp2.h index 9e7fa5667..408d90371 100644 --- a/src/lib/openjp2/jp2.h +++ b/src/lib/openjp2/jp2.h @@ -235,6 +235,15 @@ Decoding parameters are returned in jp2->j2k->cp. */ void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters); +/** +Set the strict mode parameter. When strict mode is enabled, the entire +bitstream must be decoded or an error is returned. When it is disabled, +the decoder will decode partial bitstreams. +@param jp2 JP2 decompressor handle +@param strict JPH_TRUE for strict mode +*/ +void opj_jp2_decoder_set_strict_mode(opj_jp2_t *jp2, OPJ_BOOL strict); + /** Allocates worker threads for the compressor/decompressor. * * @param jp2 JP2 decompressor handle diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index 0c5f2d5f6..de5a1d042 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -219,6 +219,10 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format) l_codec->m_codec_data.m_decompression.opj_setup_decoder = (void (*)(void *, opj_dparameters_t *)) opj_j2k_setup_decoder; + l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode = + (void (*)(void *, OPJ_BOOL)) opj_j2k_decoder_set_strict_mode; + + l_codec->m_codec_data.m_decompression.opj_read_tile_header = (OPJ_BOOL(*)(void *, OPJ_UINT32*, @@ -326,6 +330,9 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format) l_codec->m_codec_data.m_decompression.opj_setup_decoder = (void (*)(void *, opj_dparameters_t *)) opj_jp2_setup_decoder; + l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode = + (void (*)(void *, OPJ_BOOL)) opj_jp2_decoder_set_strict_mode; + l_codec->m_codec_data.m_decompression.opj_set_decode_area = (OPJ_BOOL(*)(void *, opj_image_t*, @@ -426,6 +433,26 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, return OPJ_FALSE; } + OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict) + { + if (p_codec) { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + + if (! l_codec->is_decompressor) { + opj_event_msg(&(l_codec->m_event_mgr), EVT_ERROR, + "Codec provided to the opj_decoder_set_strict_mode function is not a decompressor handler.\n"); + return OPJ_FALSE; + } + + l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode(l_codec->m_codec, + strict); + return OPJ_TRUE; + } + return OPJ_FALSE; + + } + + OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream, opj_codec_t *p_codec, opj_image_t **p_image) diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index c0d6dbcb2..177379b17 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -1345,6 +1345,19 @@ OPJ_API void OPJ_CALLCONV opj_set_default_decoder_parameters( OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, opj_dparameters_t *parameters); +/** + * Set strict decoding parameter for this decoder. If strict decoding is enabled, partial bit + * streams will fail to decode. If strict decoding is disabled, the decoder will decode partial + * bitstreams as much as possible without erroring + * + * @param p_codec decompressor handler + * @param strict OBJ_TRUE to enable strict decoding, OBJ_FALSE to disable + * + * @return true if the decoder is correctly set + */ + + OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict); + /** * Allocates worker threads for the compressor/decompressor. * diff --git a/src/lib/openjp2/opj_codec.h b/src/lib/openjp2/opj_codec.h index 8a8af9119..7cff67082 100644 --- a/src/lib/openjp2/opj_codec.h +++ b/src/lib/openjp2/opj_codec.h @@ -90,6 +90,9 @@ typedef struct opj_codec_private { /** Setup decoder function handler */ void (*opj_setup_decoder)(void * p_codec, opj_dparameters_t * p_param); + /** Strict mode function handler */ + void (*opj_decoder_set_strict_mode)(void * p_codec, OPJ_BOOL strict); + /** Set decode area function handler */ OPJ_BOOL(*opj_set_decode_area)(void * p_codec, opj_image_t * p_image, diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index e43f3fa98..c00f8f560 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -1377,7 +1377,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, opj_tcd_cblk_dec_t* l_cblk = 00; opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; - OPJ_UINT32 partial_buffer = 0; + OPJ_BOOL partial_buffer = OPJ_FALSE; OPJ_ARG_NOT_USED(p_t2); OPJ_ARG_NOT_USED(pack_info); @@ -1427,24 +1427,32 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, (OPJ_SIZE_T)l_current_data) || (l_current_data + l_seg->newlen > p_src_data + p_max_length) || (partial_buffer)) { - opj_event_msg(p_manager, EVT_WARNING, - "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); - // skip this codeblock since it is a partial read - partial_buffer = 1; - l_cblk->numchunks = 0; - - l_seg->numpasses += l_seg->numnewpasses; - l_cblk->numnewpasses -= l_seg->numnewpasses; - if (l_cblk->numnewpasses > 0) { - ++l_seg; - ++l_cblk->numsegs; - } - if(l_cblk->numnewpasses > 0) { - break; + if(p_t2->cp->strict) { + opj_event_msg(p_manager, EVT_WARNING, + "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + return OPJ_FALSE; + } else { + opj_event_msg(p_manager, EVT_WARNING, + "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + // skip this codeblock since it is a partial read + partial_buffer = OPJ_TRUE; + l_cblk->numchunks = 0; + + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + if (l_cblk->numnewpasses > 0) { + ++l_seg; + ++l_cblk->numsegs; + } + if(l_cblk->numnewpasses > 0) { + break; + } + continue; } - continue; } #ifdef USE_JPWL @@ -1573,11 +1581,18 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2, /* Check possible overflow then size */ if (((*p_data_read + l_seg->newlen) < (*p_data_read)) || ((*p_data_read + l_seg->newlen) > p_max_length)) { - opj_event_msg(p_manager, EVT_ERROR, - "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); - //return OPJ_FALSE; + if(p_t2->cp->strict) { + opj_event_msg(p_manager, EVT_ERROR, + "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + return OPJ_FALSE; + } else { + opj_event_msg(p_manager, EVT_WARNING, + "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + } } #ifdef USE_JPWL From c9cf6de3412b6b945947904deef07e707daa7f93 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 29 Jan 2022 20:27:08 +0800 Subject: [PATCH 05/12] Fix mis-spelled OPJ_TRUE. --- src/lib/openjp2/jp2.h | 2 +- src/lib/openjp2/openjpeg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/openjp2/jp2.h b/src/lib/openjp2/jp2.h index 408d90371..173f25119 100644 --- a/src/lib/openjp2/jp2.h +++ b/src/lib/openjp2/jp2.h @@ -240,7 +240,7 @@ Set the strict mode parameter. When strict mode is enabled, the entire bitstream must be decoded or an error is returned. When it is disabled, the decoder will decode partial bitstreams. @param jp2 JP2 decompressor handle -@param strict JPH_TRUE for strict mode +@param strict OPJ_TRUE for strict mode */ void opj_jp2_decoder_set_strict_mode(opj_jp2_t *jp2, OPJ_BOOL strict); diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index 177379b17..1f42e79a1 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -1351,7 +1351,7 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, * bitstreams as much as possible without erroring * * @param p_codec decompressor handler - * @param strict OBJ_TRUE to enable strict decoding, OBJ_FALSE to disable + * @param strict OPJ_TRUE to enable strict decoding, OPJ_FALSE to disable * * @return true if the decoder is correctly set */ From 422171f796d7ae292e8e6e3c01add89e9800af35 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 29 Jan 2022 20:50:45 +0800 Subject: [PATCH 06/12] Whitespace cleanup. --- src/lib/openjp2/j2k.c | 4 ++-- src/lib/openjp2/openjpeg.c | 8 +++----- src/lib/openjp2/openjpeg.h | 2 +- src/lib/openjp2/t2.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 16dd1c318..3c88f9555 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -4966,11 +4966,11 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k, opj_stream_get_number_byte_left(p_stream)) { if(p_j2k->m_cp.strict) { opj_event_msg(p_manager, EVT_ERROR, - "Tile part length size inconsistent with stream length\n"); + "Tile part length size inconsistent with stream length\n"); return OPJ_FALSE; } else { opj_event_msg(p_manager, EVT_WARNING, - "Tile part length size inconsistent with stream length\n"); + "Tile part length size inconsistent with stream length\n"); } } if (p_j2k->m_specific_param.m_decoder.m_sot_length > diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index de5a1d042..294285afc 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -433,8 +433,8 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, return OPJ_FALSE; } - OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict) - { +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict) +{ if (p_codec) { opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; @@ -449,9 +449,7 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, return OPJ_TRUE; } return OPJ_FALSE; - - } - +} OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream, opj_codec_t *p_codec, diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index 1f42e79a1..ebaeda3c6 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -1356,7 +1356,7 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, * @return true if the decoder is correctly set */ - OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict); +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict); /** * Allocates worker threads for the compressor/decompressor. diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index c00f8f560..70a35f26a 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -1429,15 +1429,15 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, (partial_buffer)) { if(p_t2->cp->strict) { opj_event_msg(p_manager, EVT_WARNING, - "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); + "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); return OPJ_FALSE; } else { opj_event_msg(p_manager, EVT_WARNING, - "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); + "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); // skip this codeblock since it is a partial read partial_buffer = OPJ_TRUE; l_cblk->numchunks = 0; @@ -1583,15 +1583,15 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2, ((*p_data_read + l_seg->newlen) > p_max_length)) { if(p_t2->cp->strict) { opj_event_msg(p_manager, EVT_ERROR, - "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); + "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); return OPJ_FALSE; } else { opj_event_msg(p_manager, EVT_WARNING, - "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); + "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); } } From fd4a757cf840f5c8ddcd900c8e63f000f136cde2 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 29 Jan 2022 20:54:50 +0800 Subject: [PATCH 07/12] Change strict message back to ERROR. --- src/lib/openjp2/t2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 70a35f26a..3d84ebbba 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -1428,7 +1428,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, (l_current_data + l_seg->newlen > p_src_data + p_max_length) || (partial_buffer)) { if(p_t2->cp->strict) { - opj_event_msg(p_manager, EVT_WARNING, + opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); From f4088f9a74d535cd0000e6e13e0e856e6cdba1e1 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 29 Jan 2022 21:12:21 +0800 Subject: [PATCH 08/12] Add strict mode parameter to opj_decompress CLI. --- src/bin/jp2/opj_decompress.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index f00f1403e..57721fbb3 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -153,6 +153,8 @@ typedef struct opj_decompress_params { int num_threads; /* Quiet */ int quiet; + /* Strict decoding mode */ + int strict; /** number of components to decode */ OPJ_UINT32 numcomps; /** indices of components to decode */ @@ -246,6 +248,8 @@ static void decode_help_display(void) fprintf(stdout, " -threads \n" " Number of threads to use for decoding or ALL_CPUS for all available cores.\n"); } + fprintf(stdout, " -strict\n" + " Enable strict decoding mode.\n"); fprintf(stdout, " -quiet\n" " Disable output from the library and other output.\n"); /* UniPG>> */ @@ -601,6 +605,7 @@ int parse_cmdline_decoder(int argc, char **argv, {"split-pnm", NO_ARG, NULL, 1}, {"threads", REQ_ARG, NULL, 'T'}, {"quiet", NO_ARG, NULL, 1}, + {"strict", NO_ARG, NULL, 1}, }; const char optlist[] = "i:o:r:l:x:d:t:p:c:" @@ -616,6 +621,7 @@ int parse_cmdline_decoder(int argc, char **argv, long_option[3].flag = &(parameters->upsample); long_option[4].flag = &(parameters->split_pnm); long_option[6].flag = &(parameters->quiet); + long_option[7].flag = &(parameters->strict); totlen = sizeof(long_option); opj_reset_options_reading(); img_fol->set_out_format = 0; @@ -1491,6 +1497,15 @@ int main(int argc, char **argv) goto fin; } + /* Set strict mode. */ + if (!opj_decoder_set_strict_mode(l_codec, parameters.strict)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to set strict mode\n"); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + failed = 1; + goto fin; + } + if (parameters.num_threads >= 1 && !opj_codec_set_threads(l_codec, parameters.num_threads)) { fprintf(stderr, "ERROR -> opj_decompress: failed to set number of threads\n"); From 2abbcb9ef7a5cac5d034004207e515a7339d28ff Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 29 Jan 2022 22:56:26 +0800 Subject: [PATCH 09/12] Fix code-style and merge duplicate if block. --- src/lib/openjp2/j2k.c | 2 +- src/lib/openjp2/openjpeg.c | 8 +++++--- src/lib/openjp2/openjpeg.h | 3 ++- src/lib/openjp2/t2.c | 16 +++++++--------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 3c88f9555..b7308d8d6 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -4964,7 +4964,7 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k, /* Check enough bytes left in stream before allocation */ if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) { - if(p_j2k->m_cp.strict) { + if (p_j2k->m_cp.strict) { opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n"); return OPJ_FALSE; diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index 294285afc..29d3ee528 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -433,7 +433,8 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, return OPJ_FALSE; } -OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict) +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, + OPJ_BOOL strict) { if (p_codec) { opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; @@ -444,8 +445,9 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, return OPJ_FALSE; } - l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode(l_codec->m_codec, - strict); + l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode( + l_codec->m_codec, + strict); return OPJ_TRUE; } return OPJ_FALSE; diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index ebaeda3c6..ebce53db0 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -1356,7 +1356,8 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec, * @return true if the decoder is correctly set */ -OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict); +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, + OPJ_BOOL strict); /** * Allocates worker threads for the compressor/decompressor. diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 3d84ebbba..ebda00526 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -1399,9 +1399,9 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, // if we have a partial data stream, set numchunks to zero // since we have no data to actually decode. - if(partial_buffer) { + if (partial_buffer) { l_cblk->numchunks = 0; - } + } if (!l_cblk->numnewpasses) { /* nothing to do */ @@ -1425,14 +1425,14 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, /* Check possible overflow (on l_current_data only, assumes input args already checked) then size */ if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) < (OPJ_SIZE_T)l_current_data) || - (l_current_data + l_seg->newlen > p_src_data + p_max_length) || + (l_current_data + l_seg->newlen > p_src_data + p_max_length) || (partial_buffer)) { - if(p_t2->cp->strict) { + if (p_t2->cp->strict) { opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); - return OPJ_FALSE; + return OPJ_FALSE; } else { opj_event_msg(p_manager, EVT_WARNING, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", @@ -1447,8 +1447,6 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, if (l_cblk->numnewpasses > 0) { ++l_seg; ++l_cblk->numsegs; - } - if(l_cblk->numnewpasses > 0) { break; } continue; @@ -1515,7 +1513,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, } // return the number of bytes read - if(partial_buffer) { + if (partial_buffer) { *(p_data_read) = p_max_length; } else { *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); @@ -1581,7 +1579,7 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2, /* Check possible overflow then size */ if (((*p_data_read + l_seg->newlen) < (*p_data_read)) || ((*p_data_read + l_seg->newlen) > p_max_length)) { - if(p_t2->cp->strict) { + if (p_t2->cp->strict) { opj_event_msg(p_manager, EVT_ERROR, "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, From 12aef962f279681d864dfb109cca9559fdfde4ef Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 29 Jan 2022 23:12:46 +0800 Subject: [PATCH 10/12] Make sure strict mode is enabled by default. --- src/lib/openjp2/j2k.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index b7308d8d6..e7c03ae13 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -6690,7 +6690,6 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) if (j2k && parameters) { j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer; j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce; - j2k->m_cp.strict = OPJ_TRUE; j2k->dump_state = (parameters->flags & OPJ_DPARAMETERS_DUMP_FLAG); #ifdef USE_JPWL @@ -10422,6 +10421,9 @@ opj_j2k_t* opj_j2k_create_decompress(void) /* per component is allowed */ l_j2k->m_cp.allow_different_bit_depth_sign = 1; + /* Default to using strict mode. */ + l_j2k->m_cp.strict = OPJ_TRUE; + #ifdef OPJ_DISABLE_TPSOT_FIX l_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1; #endif From 3db5f0e48cb841e5394929714e9c1b3ac7211049 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sun, 30 Jan 2022 00:18:32 +0800 Subject: [PATCH 11/12] Change opj_decompress back to strict mode. --- src/bin/jp2/opj_decompress.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index 57721fbb3..7b784fc7b 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -153,8 +153,8 @@ typedef struct opj_decompress_params { int num_threads; /* Quiet */ int quiet; - /* Strict decoding mode */ - int strict; + /* Allow partial decode */ + int allow_partial; /** number of components to decode */ OPJ_UINT32 numcomps; /** indices of components to decode */ @@ -248,8 +248,8 @@ static void decode_help_display(void) fprintf(stdout, " -threads \n" " Number of threads to use for decoding or ALL_CPUS for all available cores.\n"); } - fprintf(stdout, " -strict\n" - " Enable strict decoding mode.\n"); + fprintf(stdout, " -allow-partial\n" + " Disable strict mode to allow decoding partial codestreams.\n"); fprintf(stdout, " -quiet\n" " Disable output from the library and other output.\n"); /* UniPG>> */ @@ -605,7 +605,7 @@ int parse_cmdline_decoder(int argc, char **argv, {"split-pnm", NO_ARG, NULL, 1}, {"threads", REQ_ARG, NULL, 'T'}, {"quiet", NO_ARG, NULL, 1}, - {"strict", NO_ARG, NULL, 1}, + {"allow-partial", NO_ARG, NULL, 1}, }; const char optlist[] = "i:o:r:l:x:d:t:p:c:" @@ -621,7 +621,7 @@ int parse_cmdline_decoder(int argc, char **argv, long_option[3].flag = &(parameters->upsample); long_option[4].flag = &(parameters->split_pnm); long_option[6].flag = &(parameters->quiet); - long_option[7].flag = &(parameters->strict); + long_option[7].flag = &(parameters->allow_partial); totlen = sizeof(long_option); opj_reset_options_reading(); img_fol->set_out_format = 0; @@ -1497,9 +1497,9 @@ int main(int argc, char **argv) goto fin; } - /* Set strict mode. */ - if (!opj_decoder_set_strict_mode(l_codec, parameters.strict)) { - fprintf(stderr, "ERROR -> opj_decompress: failed to set strict mode\n"); + /* Disable strict mode if we want to decode partial codestreams. */ + if (parameters.allow_partial && !opj_decoder_set_strict_mode(l_codec, OPJ_FALSE)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to disable strict mode\n"); opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); failed = 1; From dc088f772d45a81940bb45d7d18f398428d8f7cc Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sun, 30 Jan 2022 01:06:02 +0800 Subject: [PATCH 12/12] Fix ident. --- src/bin/jp2/opj_decompress.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index 7b784fc7b..c32cc3dc6 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -1498,7 +1498,8 @@ int main(int argc, char **argv) } /* Disable strict mode if we want to decode partial codestreams. */ - if (parameters.allow_partial && !opj_decoder_set_strict_mode(l_codec, OPJ_FALSE)) { + if (parameters.allow_partial && + !opj_decoder_set_strict_mode(l_codec, OPJ_FALSE)) { fprintf(stderr, "ERROR -> opj_decompress: failed to disable strict mode\n"); opj_stream_destroy(l_stream); opj_destroy_codec(l_codec);