[trunk] Import patch from sumatrapdf team. This handle some Part-2 compliant file...
[openjpeg.git] / src / lib / openjp2 / jp2.c
index 9dde2e97485f86ed6c2ededf78786fec0485b896..f8eb907d631988ba89d185e21732edf82a9a619a 100644 (file)
@@ -752,6 +752,77 @@ void opj_jp2_free_pclr(opj_jp2_color_t *color)
     opj_free(color->jp2_pclr); color->jp2_pclr = NULL;
 }
 
+static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, opj_event_mgr_t *p_manager)
+{
+       OPJ_UINT16 i;
+
+       /* testcase 4149.pdf.SIGSEGV.cf7.3501 */
+       if (color->jp2_cdef) {
+               opj_jp2_cdef_info_t *info = color->jp2_cdef->info;
+               OPJ_UINT16 n = color->jp2_cdef->n;
+
+               for (i = 0; i < n; i++) {
+                       if (info[i].cn >= image->numcomps) {
+                               opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, image->numcomps);
+                               return OPJ_FALSE;
+                       }
+                       if (info[i].asoc > 0 && (OPJ_UINT32)(info[i].asoc - 1) >= image->numcomps) {
+                               opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, image->numcomps);
+                               return OPJ_FALSE;
+                       }
+               }
+       }
+
+       /* testcases 451.pdf.SIGSEGV.f4c.3723, 451.pdf.SIGSEGV.5b5.3723 and
+          66ea31acbb0f23a2bbc91f64d69a03f5_signal_sigsegv_13937c0_7030_5725.pdf */
+       if (color->jp2_pclr && color->jp2_pclr->cmap) {
+               OPJ_UINT16 nr_channels = color->jp2_pclr->nr_channels;
+               opj_jp2_cmap_comp_t *cmap = color->jp2_pclr->cmap;
+               OPJ_BOOL *pcol_usage, is_sane = OPJ_TRUE;
+
+               /* verify that all original components match an existing one */
+               for (i = 0; i < nr_channels; i++) {
+                       if (cmap[i].cmp >= image->numcomps) {
+                               opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", cmap[i].cmp, image->numcomps);
+                               is_sane = OPJ_FALSE;
+                       }
+               }
+
+               pcol_usage = opj_calloc(nr_channels, sizeof(OPJ_BOOL));
+               if (!pcol_usage) {
+                       opj_event_msg(p_manager, EVT_ERROR, "Unexpected OOM.\n");
+                       return OPJ_FALSE;
+               }
+               /* verify that no component is targeted more than once */
+               for (i = 0; i < nr_channels; i++) {
+                       OPJ_UINT16 pcol = cmap[i].pcol;
+                       if (pcol >= nr_channels) {
+                               opj_event_msg(p_manager, EVT_ERROR, "Invalid component/palette index for direct mapping %d.\n", pcol);
+                               is_sane = OPJ_FALSE;
+                       }
+                       else if (pcol_usage[pcol]) {
+                               opj_event_msg(p_manager, EVT_ERROR, "Component %d is mapped twice.\n", pcol);
+                               is_sane = OPJ_FALSE;
+                       }
+                       else
+                               pcol_usage[pcol] = OPJ_TRUE;
+               }
+               /* verify that all components are targeted at least once */
+               for (i = 0; i < nr_channels; i++) {
+                       if (!pcol_usage[i]) {
+                               opj_event_msg(p_manager, EVT_ERROR, "Component %d doesn't have a mapping.\n", i);
+                               is_sane = OPJ_FALSE;
+                       }
+               }
+               opj_free(pcol_usage);
+               if (!is_sane) {
+                       return OPJ_FALSE;
+               }
+       }
+
+       return OPJ_TRUE;
+}
+
 void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color)
 {
        opj_image_comp_t *old_comps, *new_comps;
@@ -909,6 +980,11 @@ OPJ_BOOL opj_jp2_read_pclr(        opj_jp2_t *jp2,
                for(i = 0; i < nr_channels; ++i) {
                        OPJ_INT32 bytes_to_read = (channel_size[i]+7)>>3;
 
+                       if (bytes_to_read > sizeof(OPJ_UINT32))
+                               bytes_to_read = sizeof(OPJ_UINT32);
+                       if ((ptrdiff_t)p_pclr_header_size < p_pclr_header_data - orig_header_data + bytes_to_read)
+                               return OPJ_FALSE;
+
                        if (bytes_to_read > sizeof(OPJ_UINT32))
                                bytes_to_read = sizeof(OPJ_UINT32);
                        if ((ptrdiff_t)p_pclr_header_size < p_pclr_header_data - orig_header_data + bytes_to_read)
@@ -960,6 +1036,11 @@ OPJ_BOOL opj_jp2_read_cmap(       opj_jp2_t * jp2,
                return OPJ_FALSE;
        }
 
+       if (p_cmap_header_size < (OPJ_UINT32)nr_channels * 4) {
+               opj_event_msg(p_manager, EVT_ERROR, "Insufficient data for CMAP box.\n");
+               return OPJ_FALSE;
+       }
+
        cmap = (opj_jp2_cmap_comp_t*) opj_malloc(nr_channels * sizeof(opj_jp2_cmap_comp_t));
     if (!cmap)
         return OPJ_FALSE;
@@ -1051,6 +1132,11 @@ OPJ_BOOL opj_jp2_read_cdef(      opj_jp2_t * jp2,
                return OPJ_FALSE;
        }
 
+       if (p_cdef_header_size < 2) {
+               opj_event_msg(p_manager, EVT_ERROR, "Insufficient data for CDEF box.\n");
+               return OPJ_FALSE;
+       }
+
        opj_read_bytes(p_cdef_header_data,&l_value ,2);                 /* N */
        p_cdef_header_data+= 2;
 
@@ -1064,6 +1150,11 @@ OPJ_BOOL opj_jp2_read_cdef(      opj_jp2_t * jp2,
                return OPJ_FALSE;
        }
 
+       if (p_cdef_header_size < 2 + (OPJ_UINT32)(OPJ_UINT16)l_value * 6) {
+               opj_event_msg(p_manager, EVT_ERROR, "Insufficient data for CDEF box.\n");
+               return OPJ_FALSE;
+       }
+
        cdef_info = (opj_jp2_cdef_info_t*) opj_malloc(l_value * sizeof(opj_jp2_cdef_info_t));
     if (!cdef_info)
         return OPJ_FALSE;
@@ -1131,10 +1222,14 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2,
        ++p_colr_header_data;
 
        if (jp2->meth == 1) {
-               if (p_colr_header_size != 7) {
-                       opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n");
+               if (p_colr_header_size < 7) {
+                       opj_event_msg(p_manager, EVT_ERROR, "Bad COLR header box (bad size: %d)\n", p_colr_header_size);
                        return OPJ_FALSE;
                }
+               if (p_colr_header_size > 7) {
+                       /* testcase Altona_Technical_v20_x4.pdf */
+                       opj_event_msg(p_manager, EVT_WARNING, "Bad COLR header box (bad size: %d)\n", p_colr_header_size);
+               }
 
                opj_read_bytes(p_colr_header_data,&jp2->enumcs ,4);                     /* EnumCS */
         
@@ -1188,6 +1283,9 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
        }
 
     if (!jp2->ignore_pclr_cmap_cdef){
+           if (!opj_jp2_check_color(p_image, &(jp2->color), p_manager)) {
+                   return OPJ_FALSE;
+           }
 
            /* Set Image Color Space */
            if (jp2->enumcs == 16)
@@ -2368,6 +2466,10 @@ OPJ_BOOL opj_jp2_get_tile(       opj_jp2_t *p_jp2,
                return OPJ_FALSE;
        }
 
+       if (!opj_jp2_check_color(p_image, &(p_jp2->color), p_manager)) {
+               return OPJ_FALSE;
+       }
+
        /* Set Image Color Space */
        if (p_jp2->enumcs == 16)
                p_image->color_space = OPJ_CLRSPC_SRGB;