Added opj_decoder_set_strict_mode() to control whether or not partial decoding is enabled

This commit is contained in:
Chris Hafey 2021-10-09 10:11:55 -05:00
parent b233d07809
commit ab4a40d62c
8 changed files with 114 additions and 24 deletions

View File

@ -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 */

View File

@ -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
@ -622,6 +624,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);
/**

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -1339,6 +1339,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.
*

View File

@ -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,

View File

@ -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;
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;
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;
}
if(l_cblk->numnewpasses > 0) {
break;
}
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