T1 decoder: check code stream errors when predictable termination is enabled and... 800/head
authorEven Rouault <even.rouault@spatialys.com>
Wed, 26 Jul 2017 19:39:50 +0000 (21:39 +0200)
committerEven Rouault <even.rouault@spatialys.com>
Wed, 26 Jul 2017 19:43:32 +0000 (21:43 +0200)
src/lib/openjp2/mqc.c
src/lib/openjp2/mqc.h
src/lib/openjp2/mqc_inl.h
src/lib/openjp2/t1.c
src/lib/openjp2/t1.h
src/lib/openjp2/tcd.c

index 5c1fe7996828dd16d57c08e2061edab1d520a467..8f69e29e39ddb53cdf190b9dede98a5fe9bfc3af 100644 (file)
@@ -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 {
index 06815ab1dd7b89128cde70618e544f8f3ef104db..0bc7b2b7c86ab61b1d5b699ddaefc573140ef2ae 100644 (file)
@@ -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 */
index 095a9fcf0946140a57c84e715a19c81f4caacdb6..832331ee683c7e1440ec1f517782582a105ffcb6 100644 (file)
@@ -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; \
index 637778b7592185e810a4cffeb16d9bbb666677ee..bd615d590a5347227f74b5dae69bd1b9fff424b7 100644 (file)
@@ -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;
 }
 
index 9d4245ebc2c8edd6393adf6049873a057ab26504..9cfdfc111b2c54b469811152c5b65995fcd8d900 100644 (file)
@@ -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);
 
 
 
index 3a38ef42390e543818d7216ebec5656f6ecdfcca..7ae0fa371d81de704584dadb51c7996689516a35 100644 (file)
@@ -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;
 }