diff --git a/src/lib/openjp2/mqc.c b/src/lib/openjp2/mqc.c index 5c1fe799..8f69e29e 100644 --- a/src/lib/openjp2/mqc.c +++ b/src/lib/openjp2/mqc.c @@ -300,6 +300,7 @@ void opj_mqc_init_enc(opj_mqc_t *mqc, OPJ_BYTE *bp) assert(*(mqc->bp) != 0xff); mqc->start = bp; + mqc->end_of_byte_stream_counter = 0; } void opj_mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d) @@ -513,6 +514,7 @@ void opj_mqc_init_dec(opj_mqc_t *mqc, OPJ_BYTE *bp, OPJ_UINT32 len, /* See https://github.com/uclouvain/openjpeg/issues/921 */ opj_mqc_init_dec_common(mqc, bp, len, extra_writable_bytes); opj_mqc_setcurctx(mqc, 0); + mqc->end_of_byte_stream_counter = 0; if (len == 0) { mqc->c = 0xff << 16; } else { diff --git a/src/lib/openjp2/mqc.h b/src/lib/openjp2/mqc.h index 06815ab1..0bc7b2b7 100644 --- a/src/lib/openjp2/mqc.h +++ b/src/lib/openjp2/mqc.h @@ -78,6 +78,8 @@ typedef struct opj_mqc { OPJ_UINT32 a; /** number of bits already read or free to write */ OPJ_UINT32 ct; + /* only used by decoder, to count the number of times a terminating 0xFF >0x8F marker is read */ + OPJ_UINT32 end_of_byte_stream_counter; /** pointer to the current position in the buffer */ OPJ_BYTE *bp; /** pointer to the start of the buffer */ diff --git a/src/lib/openjp2/mqc_inl.h b/src/lib/openjp2/mqc_inl.h index 095a9fcf..832331ee 100644 --- a/src/lib/openjp2/mqc_inl.h +++ b/src/lib/openjp2/mqc_inl.h @@ -109,6 +109,7 @@ static INLINE OPJ_UINT32 opj_mqc_raw_decode(opj_mqc_t *mqc) if (l_c > 0x8f) { \ c += 0xff00; \ ct = 8; \ + mqc->end_of_byte_stream_counter ++; \ } else { \ mqc->bp++; \ c += l_c << 9; \ diff --git a/src/lib/openjp2/t1.c b/src/lib/openjp2/t1.c index 637778b7..bd615d59 100644 --- a/src/lib/openjp2/t1.c +++ b/src/lib/openjp2/t1.c @@ -189,7 +189,10 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 orient, OPJ_UINT32 roishift, - OPJ_UINT32 cblksty); + OPJ_UINT32 cblksty, + opj_event_mgr_t *p_manager, + opj_mutex_t* p_manager_mutex, + OPJ_BOOL check_pterm); static OPJ_BOOL opj_t1_allocate_buffers(opj_t1_t *t1, OPJ_UINT32 w, @@ -1608,6 +1611,9 @@ typedef struct { opj_tcd_tilecomp_t* tilec; opj_tccp_t* tccp; volatile OPJ_BOOL* pret; + opj_event_mgr_t *p_manager; + opj_mutex_t* p_manager_mutex; + OPJ_BOOL check_pterm; } opj_t1_cblk_decode_processing_job_t; static void opj_t1_destroy_wrapper(void* t1) @@ -1654,7 +1660,10 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) cblk, band->bandno, (OPJ_UINT32)tccp->roishift, - tccp->cblksty)) { + tccp->cblksty, + job->p_manager, + job->p_manager_mutex, + job->check_pterm)) { *(job->pret) = OPJ_FALSE; opj_free(job); return; @@ -1730,7 +1739,10 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) void opj_t1_decode_cblks(opj_thread_pool_t* tp, volatile OPJ_BOOL* pret, opj_tcd_tilecomp_t* tilec, - opj_tccp_t* tccp + opj_tccp_t* tccp, + opj_event_mgr_t *p_manager, + opj_mutex_t* p_manager_mutex, + OPJ_BOOL check_pterm ) { OPJ_UINT32 resno, bandno, precno, cblkno; @@ -1760,6 +1772,9 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp, job->tilec = tilec; job->tccp = tccp; job->pret = pret; + job->p_manager_mutex = p_manager_mutex; + job->p_manager = p_manager; + job->check_pterm = check_pterm; opj_thread_pool_submit_job(tp, opj_t1_clbl_decode_processor, job); if (!(*pret)) { return; @@ -1777,7 +1792,10 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 orient, OPJ_UINT32 roishift, - OPJ_UINT32 cblksty) + OPJ_UINT32 cblksty, + opj_event_mgr_t *p_manager, + opj_mutex_t* p_manager_mutex, + OPJ_BOOL check_pterm) { opj_mqc_t *mqc = &(t1->mqc); /* MQC component */ @@ -1858,6 +1876,32 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, opq_mqc_finish_dec(mqc); } + if (check_pterm) { + if (mqc->bp + 2 < mqc->end) { + if (p_manager_mutex) { + opj_mutex_lock(p_manager_mutex); + } + opj_event_msg(p_manager, EVT_WARNING, + "PTERM check failure: %d remaining bytes in code block (%d used / %d)\n", + (int)(mqc->end - mqc->bp) - 2, + (int)(mqc->bp - mqc->start), + (int)(mqc->end - mqc->start)); + if (p_manager_mutex) { + opj_mutex_unlock(p_manager_mutex); + } + } else if (mqc->end_of_byte_stream_counter > 2) { + if (p_manager_mutex) { + opj_mutex_lock(p_manager_mutex); + } + opj_event_msg(p_manager, EVT_WARNING, + "PTERM check failure: %d synthetized 0xFF markers read\n", + mqc->end_of_byte_stream_counter); + if (p_manager_mutex) { + opj_mutex_unlock(p_manager_mutex); + } + } + } + return OPJ_TRUE; } diff --git a/src/lib/openjp2/t1.h b/src/lib/openjp2/t1.h index 9d4245eb..9cfdfc11 100644 --- a/src/lib/openjp2/t1.h +++ b/src/lib/openjp2/t1.h @@ -230,7 +230,10 @@ Decode the code-blocks of a tile void opj_t1_decode_cblks(opj_thread_pool_t* tp, volatile OPJ_BOOL* pret, opj_tcd_tilecomp_t* tilec, - opj_tccp_t* tccp); + opj_tccp_t* tccp, + opj_event_mgr_t *p_manager, + opj_mutex_t* p_manager_mutex, + OPJ_BOOL check_pterm); diff --git a/src/lib/openjp2/tcd.c b/src/lib/openjp2/tcd.c index 3a38ef42..7ae0fa37 100644 --- a/src/lib/openjp2/tcd.c +++ b/src/lib/openjp2/tcd.c @@ -157,7 +157,8 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd, opj_codestream_index_t *p_cstr_index, opj_event_mgr_t *p_manager); -static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd); +static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd); @@ -1421,8 +1422,7 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd, /*------------------TIER1-----------------*/ /* FIXME _ProfStart(PGROUP_T1); */ - if - (! opj_tcd_t1_decode(p_tcd)) { + if (! opj_tcd_t1_decode(p_tcd, p_manager)) { return OPJ_FALSE; } /* FIXME _ProfStop(PGROUP_T1); */ @@ -1681,16 +1681,27 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd, return OPJ_TRUE; } -static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd) +static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) { OPJ_UINT32 compno; opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps; opj_tccp_t * l_tccp = p_tcd->tcp->tccps; volatile OPJ_BOOL ret = OPJ_TRUE; + OPJ_BOOL check_pterm = OPJ_FALSE; + opj_mutex_t* p_manager_mutex = NULL; + + p_manager_mutex = opj_mutex_create(); + + /* Only enable PTERM check if we decode all layers */ + if (p_tcd->tcp->num_layers_to_decode == p_tcd->tcp->numlayers && + (l_tccp->cblksty & J2K_CCP_CBLKSTY_PTERM) != 0) { + check_pterm = OPJ_TRUE; + } for (compno = 0; compno < l_tile->numcomps; ++compno) { - opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp); + opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp, + p_manager, p_manager_mutex, check_pterm); if (!ret) { break; } @@ -1699,7 +1710,9 @@ static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd) } opj_thread_pool_wait_completion(p_tcd->thread_pool, 0); - + if (p_manager_mutex) { + opj_mutex_destroy(p_manager_mutex); + } return ret; }