[trunk] Import (ugly) patch from sumatrapdf team. This feels like a hack rather than...
[openjpeg.git] / src / lib / openjp2 / j2k.c
index 555c59286d9ebdae44591931d00e3a08bd58a77d..aa4f1d1dbcf35b9f79b34c5b02abcc24e9f9e29e 100644 (file)
@@ -1149,9 +1149,9 @@ static OPJ_FLOAT32 opj_j2k_get_default_stride (opj_tcp_t * p_tcp);
 
 static int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres);
 
-static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image);
+static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager);
 
-static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode);
+static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager);
 
 /*@}*/
 
@@ -1954,6 +1954,23 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                 return OPJ_FALSE;
         }
 
+        /* testcase 4035.pdf.SIGSEGV.d8b.3375 */
+        if (l_image->x0 > l_image->x1 || l_image->y0 > l_image->y1) {
+                opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0);
+                return OPJ_FALSE;
+        }
+        /* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */
+        if (!(l_cp->tdx * l_cp->tdy)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: invalid tile size (tdx: %d, tdy: %d)\n", l_cp->tdx, l_cp->tdy);
+                return OPJ_FALSE;
+        }
+
+        /* testcase 1610.pdf.SIGSEGV.59c.681 */
+        if (((OPJ_UINT64)l_image->x1) * ((OPJ_UINT64)l_image->y1) != (l_image->x1 * l_image->y1)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)", l_image->x1, l_image->y1);
+                return OPJ_FALSE;
+        }
+
 #ifdef USE_JPWL
         if (l_cp->correct) {
                 /* if JPWL is on, we check whether TX errors have damaged
@@ -3898,6 +3915,12 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
         opj_read_bytes(p_header_data,&(p_j2k->m_current_tile_number),2);                /* Isot */
         p_header_data+=2;
 
+        /* testcase 2.pdf.SIGFPE.706.1112 */
+        if (p_j2k->m_current_tile_number >= l_cp->tw * l_cp->th) {
+                opj_event_msg(p_manager, EVT_ERROR, "Invalid tile number %d\n", p_j2k->m_current_tile_number);
+                return OPJ_FALSE;
+        }
+
         l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number];
         l_tile_x = p_j2k->m_current_tile_number % l_cp->tw;
         l_tile_y = p_j2k->m_current_tile_number / l_cp->tw;
@@ -3987,20 +4010,19 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                 if (l_num_parts != 0) { /* Number of tile-part header is provided by this tile-part header */
                         /* Useful to manage the case of textGBR.jp2 file because two values of TNSot are allowed: the correct numbers of
                          * tile-parts for that tile and zero (A.4.2 of 15444-1 : 2002). */
-                        if (l_tcp->m_nb_tile_parts) {
-                                if (l_current_part >= l_tcp->m_nb_tile_parts){
-                                        opj_event_msg(p_manager, EVT_ERROR, "In SOT marker, TPSot (%d) is not valid regards to the current "
-                                                        "number of tile-part (%d), giving up\n", l_current_part, l_tcp->m_nb_tile_parts );
-                                        p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
-                                        return OPJ_FALSE;
-                                }
+                        if (l_num_parts < l_tcp->m_nb_tile_parts) {
+                                l_num_parts = l_tcp->m_nb_tile_parts;
+                        }
+                        if (l_current_part >= l_num_parts) {
+                                /* testcase 451.pdf.SIGSEGV.ce9.3723 */
+                                l_num_parts = l_current_part + 1;
                         }
                         l_tcp->m_nb_tile_parts = l_num_parts;
                 }
 
                 /* If know the number of tile part header we will check if we didn't read the last*/
                 if (l_tcp->m_nb_tile_parts) {
-                        if (l_tcp->m_nb_tile_parts == (l_current_part + 1)) {
+                        if (l_tcp->m_nb_tile_parts == l_current_part) {
                                 p_j2k->m_specific_param.m_decoder.m_can_decode = 1; /* Process the last tile-part header*/
                         }
                 }
@@ -4069,7 +4091,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
 
                                         if ( l_current_part >= p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps ){
                                                 opj_tp_index_t *new_tp_index;
-                                                p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps += 10;
+                                                p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = l_current_part + 1;
                                                 new_tp_index = (opj_tp_index_t *) opj_realloc(
                                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index,
                                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps * sizeof(opj_tp_index_t));
@@ -4459,6 +4481,14 @@ static OPJ_BOOL opj_j2k_read_rgn (opj_j2k_t *p_j2k,
         };
 #endif /* USE_JPWL */
 
+        /* testcase 3635.pdf.asan.77.2930 */
+        if (l_comp_room >= l_nb_comp) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                        "JPWL: bad component number in RGN (%d when there are only %d)\n",
+                        l_comp_room, l_nb_comp);
+                return OPJ_FALSE;
+        }
+
         opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&(l_tcp->tccps[l_comp_no].roishift)),1);   /* SPrgn */
         ++p_header_data;
 
@@ -5808,7 +5838,7 @@ int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){
     return 2;
 }
 
-void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image)
+void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager)
 {
     /* Configure cinema parameters */
     float max_rate = 0;
@@ -5860,7 +5890,8 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
 
     /* Number of layers */
     if (parameters->tcp_numlayers > 1){
-        fprintf(stdout,"JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+        opj_event_msg(p_manager, EVT_WARNING,
+                "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
                 "1 single quality layer"
                 "-> Number of layers forced to 1 (rather than %d)\n",
                 parameters->tcp_numlayers);
@@ -5872,7 +5903,8 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
     case OPJ_CINEMA2K_24:
     case OPJ_CINEMA2K_48:
         if(parameters->numresolution > 6){
-            fprintf(stdout,"JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
                     "Number of decomposition levels <= 5\n"
                     "-> Number of decomposition levels forced to 5 (rather than %d)\n",
                     parameters->numresolution+1);
@@ -5881,13 +5913,15 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
         break;
     case OPJ_CINEMA4K_24:
         if(parameters->numresolution < 2){
-            fprintf(stdout,"JPEG 2000 Profile-4 (4k dc profile) requires:\n"
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
                     "Number of decomposition levels >= 1 && <= 6\n"
                     "-> Number of decomposition levels forced to 1 (rather than %d)\n",
                     parameters->numresolution+1);
             parameters->numresolution = 1;
         }else if(parameters->numresolution > 7){
-            fprintf(stdout,"JPEG 2000 Profile-4 (4k dc profile) requires:\n"
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
                     "Number of decomposition levels >= 1 && <= 6\n"
                     "-> Number of decomposition levels forced to 6 (rather than %d)\n",
                     parameters->numresolution+1);
@@ -5929,13 +5963,15 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
             temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
                     (parameters->tcp_rates[0] * 8 * image->comps[0].dx * image->comps[0].dy);
             if (temp_rate > CINEMA_24_CS ){
-                fprintf(stdout,"JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
                         "Maximum 1302083 compressed bytes @ 24fps\n"
                         "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n",
                         parameters->tcp_rates[0], max_rate);
                 parameters->tcp_rates[0]= max_rate;
             }else{
-                fprintf(stdout,"JPEG 2000 Profile-3 and 4 (2k/4k dc profile):\n"
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 and 4 (2k/4k dc profile):\n"
                         "INFO : Specified rate (%3.1f) is below the 2k/4k limit @ 24fps.\n",
                         parameters->tcp_rates[0]);
             }
@@ -5951,13 +5987,15 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
             temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
                     (parameters->tcp_rates[0] * 8 * image->comps[0].dx * image->comps[0].dy);
             if (temp_rate > CINEMA_48_CS ){
-                fprintf(stdout,"JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
                         "Maximum 651041 compressed bytes @ 48fps\n"
                         "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n",
                         parameters->tcp_rates[0], max_rate);
                 parameters->tcp_rates[0]= max_rate;
             }else{
-                fprintf(stdout,"JPEG 2000 Profile-3 (2k dc profile):\n"
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 (2k dc profile):\n"
                         "INFO : Specified rate (%3.1f) is below the 2k limit @ 48 fps.\n",
                         parameters->tcp_rates[0]);
             }
@@ -5969,13 +6007,14 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
     }
 }
 
-OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode)
+OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager)
 {
     OPJ_UINT32 i;
 
     /* Number of components */
     if (image->numcomps != 3){
-        fprintf(stdout,"JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+        opj_event_msg(p_manager, EVT_WARNING,
+                "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
                 "3 components"
                 "-> Number of components of input image (%d) is not compliant\n"
                 "-> Non-profile-3 codestream will be generated\n",
@@ -5989,7 +6028,8 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_
             char signed_str[] = "signed";
             char unsigned_str[] = "unsigned";
             char *tmp_str = image->comps[i].sgnd?signed_str:unsigned_str;
-            fprintf(stdout,"JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
                     "Precision of each component shall be 12 bits unsigned"
                     "-> At least component %d of input image (%d bits, %s) is not compliant\n"
                     "-> Non-profile-3 codestream will be generated\n",
@@ -6003,7 +6043,8 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_
     case OPJ_CINEMA2K_24:
     case OPJ_CINEMA2K_48:
         if (((image->comps[0].w > 2048) | (image->comps[0].h > 1080))){
-            fprintf(stdout,"JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
                     "width <= 2048 and height <= 1080\n"
                     "-> Input image size %d x %d is not compliant\n"
                     "-> Non-profile-3 codestream will be generated\n",
@@ -6013,7 +6054,8 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_
         break;
     case OPJ_CINEMA4K_24:
         if (((image->comps[0].w > 4096) | (image->comps[0].h > 2160))){
-            fprintf(stdout,"JPEG 2000 Profile-4 (4k dc profile) requires:\n"
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
                     "width <= 4096 and height <= 2160\n"
                     "-> Image size %d x %d is not compliant\n"
                     "-> Non-profile-4 codestream will be generated\n",
@@ -6049,8 +6091,8 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
 
         /* set cinema parameters if required */
         if (parameters->cp_cinema){
-            opj_j2k_set_cinema_parameters(parameters,image);
-            if (!opj_j2k_is_cinema_compliant(image,parameters->cp_cinema)) {
+            opj_j2k_set_cinema_parameters(parameters,image,p_manager);
+            if (!opj_j2k_is_cinema_compliant(image,parameters->cp_cinema,p_manager)) {
                 parameters->cp_rsiz = OPJ_STD_RSIZ;
             }
         }
@@ -7325,6 +7367,12 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
                         /* Read 2 bytes from the buffer as the marker size */
                         opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2);
 
+                        /* cf. https://code.google.com/p/openjpeg/issues/detail?id=226 */
+                        if (l_current_marker == 0x8080 && opj_stream_get_number_byte_left(p_stream) == 0) {
+                                p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
+                                break;
+                        }
+
                         /* Why this condition? FIXME */
                         if (p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH){
                                 p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2);