X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fopenjp2%2Fjp2.c;h=a607c8a944b5b8a973c4d3e977ea90609d00140a;hb=72deb588cbc8d5f56f8b0db3a2d120913e792cb8;hp=654c606ee1d2f046c3991498b75c4555957d02f6;hpb=50a205d20f25d26e77299f5bf8e62e1aa038d2b7;p=openjpeg.git diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index 654c606e..a607c8a9 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -94,7 +94,7 @@ static OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, * @param p_bpc_header_size the size of the bpc header * @param p_manager the user event manager. * - * @return true if the bpc header is valid, fale else. + * @return true if the bpc header is valid, false else. */ static OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, OPJ_BYTE * p_bpc_header_data, @@ -106,7 +106,18 @@ static OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, OPJ_UINT32 p_cdef_header_size, opj_event_mgr_t * p_manager ); -static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color); +static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color, opj_event_mgr_t *); + +/** + * Writes the Channel Definition box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. + */ +static OPJ_BYTE * opj_jp2_write_cdef( opj_jp2_t *jp2, + OPJ_UINT32 * p_nb_bytes_written ); /** * Writes the Colour Specification box. @@ -147,7 +158,7 @@ static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); -OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); @@ -159,13 +170,26 @@ OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, * @param p_header_size the size of the data contained in the file header box. * @param p_manager the user event manager. * - * @return true if the JP2 Header box was successfully reconized. + * @return true if the JP2 Header box was successfully recognized. */ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, OPJ_BYTE *p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); +/** + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param jp2 the jpeg2000 file codec. + * @param stream the stream to write data to. + * @param p_manager user event manager. + * + * @return true if writing was successful. + */ +static OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, + opj_stream_private_t *stream, + opj_event_mgr_t * p_manager ); + /** * Writes the Jpeg2000 codestream Header box - JP2C Header box. This function must be called AFTER the coding has been done. * @@ -287,7 +311,7 @@ static OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, * @param p_colr_header_size the size of the color header * @param p_manager the user event manager. * - * @return true if the bpc header is valid, fale else. + * @return true if the bpc header is valid, false else. */ static OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, OPJ_BYTE * p_colr_header_data, @@ -302,13 +326,13 @@ static OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, * Sets up the procedures to do on writing header after the codestream. * Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_end_header_writing (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_end_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Sets up the procedures to do on reading header after the codestream. * Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_end_header_reading (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_end_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Reads a jpeg2000 file header structure. @@ -346,7 +370,7 @@ static OPJ_BOOL opj_jp2_exec ( opj_jp2_t * jp2, * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). * @param p_manager user event manager. * - * @return true if the box is reconized, false otherwise + * @return true if the box is recognized, false otherwise */ static OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read, @@ -357,14 +381,14 @@ static OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_jp2_setup_encoding_validation (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_encoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Sets up the procedures to do on writing header. Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_header_writing (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); -OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); @@ -386,14 +410,14 @@ static const opj_jp2_header_handler_t * opj_jp2_img_find_handler (OPJ_UINT32 p_i */ static const opj_jp2_header_handler_t * opj_jp2_find_handler (OPJ_UINT32 p_id ); -const opj_jp2_header_handler_t jp2_header [] = +static const opj_jp2_header_handler_t jp2_header [] = { {JP2_JP,opj_jp2_read_jp}, {JP2_FTYP,opj_jp2_read_ftyp}, {JP2_JP2H,opj_jp2_read_jp2h} }; -const opj_jp2_header_handler_t jp2_img_header [] = +static const opj_jp2_header_handler_t jp2_img_header [] = { {JP2_IHDR,opj_jp2_read_ihdr}, {JP2_COLR,opj_jp2_read_colr}, @@ -413,7 +437,7 @@ const opj_jp2_header_handler_t jp2_img_header [] = * @param p_box_max_size the maximum number of bytes in the box. * @param p_manager FIXME DOC * - * @return true if the box is reconized, false otherwise + * @return true if the box is recognized, false otherwise */ static OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, OPJ_BYTE * p_data, @@ -425,16 +449,16 @@ static OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_jp2_setup_decoding_validation (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_decoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Sets up the procedures to do on reading header. * Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /* ----------------------------------------------------------------------- */ - OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, +static OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) @@ -458,12 +482,16 @@ static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); opj_read_bytes(l_data_header+4,&(box->type), 4); if(box->length == 0)/* last box */ - { + { const OPJ_OFF_T bleft = opj_stream_get_number_byte_left(cio); - box->length = (OPJ_UINT32)bleft; - assert( (OPJ_OFF_T)box->length == bleft ); - return OPJ_TRUE; + if (bleft > (OPJ_OFF_T)(0xFFFFFFFFU - 8U)) { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return OPJ_FALSE; } + box->length = (OPJ_UINT32)bleft + 8U; + assert( (OPJ_OFF_T)box->length == bleft + 8 ); + return OPJ_TRUE; + } /* do we have a "special very large box ?" */ /* read then the XLBox */ @@ -514,7 +542,7 @@ static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { } #endif -OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, OPJ_BYTE *p_image_header_data, OPJ_UINT32 p_image_header_size, opj_event_mgr_t * p_manager ) @@ -562,7 +590,7 @@ OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, +static OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written ) { @@ -612,18 +640,19 @@ OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, return l_ihdr_data; } -OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, +static OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written ) { OPJ_UINT32 i; /* room for 8 bytes for box and 1 byte for each component */ - OPJ_UINT32 l_bpcc_size = 8 + jp2->numcomps; + OPJ_UINT32 l_bpcc_size; OPJ_BYTE * l_bpcc_data,* l_current_bpcc_ptr; /* preconditions */ assert(jp2 != 00); assert(p_nb_bytes_written != 00); + l_bpcc_size = 8 + jp2->numcomps; l_bpcc_data = (OPJ_BYTE *) opj_calloc(1,l_bpcc_size); if (l_bpcc_data == 00) { @@ -648,7 +677,7 @@ OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, return l_bpcc_data; } -OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, OPJ_BYTE * p_bpc_header_data, OPJ_UINT32 p_bpc_header_size, opj_event_mgr_t * p_manager @@ -680,15 +709,64 @@ OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, return OPJ_TRUE; } +static OPJ_BYTE * opj_jp2_write_cdef(opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written) +{ + /* room for 8 bytes for box, 2 for n */ + OPJ_UINT32 l_cdef_size = 10; + OPJ_BYTE * l_cdef_data,* l_current_cdef_ptr; + OPJ_UINT32 l_value; + OPJ_UINT16 i; + + /* preconditions */ + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + assert(jp2->color.jp2_cdef != 00); + assert(jp2->color.jp2_cdef->info != 00); + assert(jp2->color.jp2_cdef->n > 0U); + + l_cdef_size += 6U * jp2->color.jp2_cdef->n; + + l_cdef_data = (OPJ_BYTE *) opj_malloc(l_cdef_size); + if (l_cdef_data == 00) { + return 00; + } + + l_current_cdef_ptr = l_cdef_data; + + opj_write_bytes(l_current_cdef_ptr,l_cdef_size,4); /* write box size */ + l_current_cdef_ptr += 4; + + opj_write_bytes(l_current_cdef_ptr,JP2_CDEF,4); /* BPCC */ + l_current_cdef_ptr += 4; + + l_value = jp2->color.jp2_cdef->n; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* N */ + l_current_cdef_ptr += 2; + + for (i = 0U; i < jp2->color.jp2_cdef->n; ++i) { + l_value = jp2->color.jp2_cdef->info[i].cn; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Cni */ + l_current_cdef_ptr += 2; + l_value = jp2->color.jp2_cdef->info[i].typ; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Typi */ + l_current_cdef_ptr += 2; + l_value = jp2->color.jp2_cdef->info[i].asoc; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Asoci */ + l_current_cdef_ptr += 2; + } + *p_nb_bytes_written = l_cdef_size; + + return l_cdef_data; +} -OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, +static OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written ) { /* room for 8 bytes for box 3 for common data and variable upon profile*/ OPJ_UINT32 l_colr_size = 11; OPJ_BYTE * l_colr_data,* l_current_colr_ptr; - + /* preconditions */ assert(jp2 != 00); assert(p_nb_bytes_written != 00); @@ -745,7 +823,7 @@ OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, return l_colr_data; } -void opj_jp2_free_pclr(opj_jp2_color_t *color) +static void opj_jp2_free_pclr(opj_jp2_color_t *color) { opj_free(color->jp2_pclr->channel_sign); opj_free(color->jp2_pclr->channel_size); @@ -764,17 +842,41 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, if (color->jp2_cdef) { opj_jp2_cdef_info_t *info = color->jp2_cdef->info; OPJ_UINT16 n = color->jp2_cdef->n; + OPJ_UINT32 nr_channels = image->numcomps; /* FIXME image->numcomps == jp2->numcomps before color is applied ??? */ + + /* cdef applies to cmap channels if any */ + if (color->jp2_pclr && color->jp2_pclr->cmap) { + nr_channels = (OPJ_UINT32)color->jp2_pclr->nr_channels; + } 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); + if (info[i].cn >= nr_channels) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, nr_channels); 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); + if (info[i].asoc == 65535U) continue; + + if (info[i].asoc > 0 && (OPJ_UINT32)(info[i].asoc - 1) >= nr_channels) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, nr_channels); return OPJ_FALSE; } } + + /* issue 397 */ + /* ISO 15444-1 states that if cdef is present, it shall contain a complete list of channel definitions. */ + while (nr_channels > 0) + { + for(i = 0; i < n; ++i) { + if ((OPJ_UINT32)info[i].cn == (nr_channels - 1U)) { + break; + } + } + if (i == n) { + opj_event_msg(p_manager, EVT_ERROR, "Incomplete channel definitions.\n"); + return OPJ_FALSE; + } + --nr_channels; + } } /* testcases 451.pdf.SIGSEGV.f4c.3723, 451.pdf.SIGSEGV.5b5.3723 and @@ -792,7 +894,7 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, } } - pcol_usage = opj_calloc(nr_channels, sizeof(OPJ_BOOL)); + pcol_usage = (OPJ_BOOL *) opj_calloc(nr_channels, sizeof(OPJ_BOOL)); if (!pcol_usage) { opj_event_msg(p_manager, EVT_ERROR, "Unexpected OOM.\n"); return OPJ_FALSE; @@ -825,6 +927,23 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, is_sane = OPJ_FALSE; } } + /* Issue 235/447 weird cmap */ + if (1 && is_sane && (image->numcomps==1U)) { + for (i = 0; i < nr_channels; i++) { + if (!pcol_usage[i]) { + is_sane = 0U; + opj_event_msg(p_manager, EVT_WARNING, "Component mapping seems wrong. Trying to correct.\n", i); + break; + } + } + if (!is_sane) { + is_sane = OPJ_TRUE; + for (i = 0; i < nr_channels; i++) { + cmap[i].mtyp = 1U; + cmap[i].pcol = (OPJ_BYTE) i; + } + } + } opj_free(pcol_usage); if (!is_sane) { return OPJ_FALSE; @@ -835,7 +954,7 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, } /* file9.jp2 */ -void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) +static void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) { opj_image_comp_t *old_comps, *new_comps; OPJ_BYTE *channel_size, *channel_sign; @@ -855,7 +974,11 @@ void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) old_comps = image->comps; new_comps = (opj_image_comp_t*) opj_malloc(nr_channels * sizeof(opj_image_comp_t)); - + if (!new_comps) { + /* FIXME no error code for opj_jp2_apply_pclr */ + /* FIXME event manager error callback */ + return; + } for(i = 0; i < nr_channels; ++i) { pcol = cmap[i].pcol; cmp = cmap[i].cmp; @@ -871,6 +994,13 @@ void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) /* Palette mapping: */ new_comps[i].data = (OPJ_INT32*) opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(OPJ_INT32)); + if (!new_comps[i].data) { + opj_free(new_comps); + new_comps = NULL; + /* FIXME no error code for opj_jp2_apply_pclr */ + /* FIXME event manager error callback */ + return; + } new_comps[i].prec = channel_size[i]; new_comps[i].sgnd = channel_sign[i]; } @@ -920,7 +1050,7 @@ void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) }/* apply_pclr() */ -OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, OPJ_BYTE * p_pclr_header_data, OPJ_UINT32 p_pclr_header_size, opj_event_mgr_t * p_manager @@ -949,12 +1079,20 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, opj_read_bytes(p_pclr_header_data, &l_value , 2); /* NE */ p_pclr_header_data += 2; nr_entries = (OPJ_UINT16) l_value; + if ((nr_entries == 0U) || (nr_entries > 1024U)) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports %d entries\n", (int)nr_entries); + return OPJ_FALSE; + } opj_read_bytes(p_pclr_header_data, &l_value , 1); /* NPC */ ++p_pclr_header_data; nr_channels = (OPJ_UINT16) l_value; + if (nr_channels == 0U) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports 0 palette columns\n"); + return OPJ_FALSE; + } - if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels || nr_channels == 0 || nr_entries >= (OPJ_UINT32)-1 / nr_channels) + if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels) return OPJ_FALSE; entries = (OPJ_UINT32*) opj_malloc((size_t)nr_channels * nr_entries * sizeof(OPJ_UINT32)); @@ -1006,7 +1144,7 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, 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 + (ptrdiff_t)bytes_to_read) + if ((ptrdiff_t)p_pclr_header_size < (ptrdiff_t)(p_pclr_header_data - orig_header_data) + (ptrdiff_t)bytes_to_read) return OPJ_FALSE; opj_read_bytes(p_pclr_header_data, &l_value , bytes_to_read); /* Cji */ @@ -1019,7 +1157,7 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, OPJ_BYTE * p_cmap_header_data, OPJ_UINT32 p_cmap_header_size, opj_event_mgr_t * p_manager @@ -1079,55 +1217,71 @@ OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, return OPJ_TRUE; } -void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color) +static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color, opj_event_mgr_t *manager) { opj_jp2_cdef_info_t *info; OPJ_UINT16 i, n, cn, asoc, acn; - + info = color->jp2_cdef->info; n = color->jp2_cdef->n; - - for(i = 0; i < n; ++i) - { - /* WATCH: acn = asoc - 1 ! */ - asoc = info[i].asoc; - if(asoc == 0 || asoc == 65535) - { - if (i < image->numcomps) - image->comps[i].alpha = info[i].typ; - continue; - } - - cn = info[i].cn; - acn = (OPJ_UINT16)(asoc - 1); - if( cn >= image->numcomps || acn >= image->numcomps ) - { - fprintf(stderr, "cn=%d, acn=%d, numcomps=%d\n", cn, acn, image->numcomps); - continue; - } - - if(cn != acn) + + for(i = 0; i < n; ++i) + { + /* WATCH: acn = asoc - 1 ! */ + asoc = info[i].asoc; + cn = info[i].cn; + + if( cn >= image->numcomps) + { + opj_event_msg(manager, EVT_WARNING, "opj_jp2_apply_cdef: cn=%d, numcomps=%d\n", cn, image->numcomps); + continue; + } + if(asoc == 0 || asoc == 65535) + { + image->comps[cn].alpha = info[i].typ; + continue; + } + + acn = (OPJ_UINT16)(asoc - 1); + if( acn >= image->numcomps ) + { + opj_event_msg(manager, EVT_WARNING, "opj_jp2_apply_cdef: acn=%d, numcomps=%d\n", acn, image->numcomps); + continue; + } + + /* Swap only if color channel */ + if((cn != acn) && (info[i].typ == 0)) { opj_image_comp_t saved; - + OPJ_UINT16 j; + memcpy(&saved, &image->comps[cn], sizeof(opj_image_comp_t)); memcpy(&image->comps[cn], &image->comps[acn], sizeof(opj_image_comp_t)); memcpy(&image->comps[acn], &saved, sizeof(opj_image_comp_t)); - - info[i].asoc = (OPJ_UINT16)(cn + 1); - info[acn].asoc = (OPJ_UINT16)(info[acn].cn + 1); + + /* Swap channels in following channel definitions, don't bother with j <= i that are already processed */ + for (j = (OPJ_UINT16)(i + 1U); j < n ; ++j) + { + if (info[j].cn == cn) { + info[j].cn = acn; + } + else if (info[j].cn == acn) { + info[j].cn = cn; + } + /* asoc is related to color index. Do not update. */ + } } - + image->comps[cn].alpha = info[i].typ; } - + if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); - + opj_free(color->jp2_cdef); color->jp2_cdef = NULL; - + }/* jp2_apply_cdef() */ -OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, OPJ_BYTE * p_cdef_header_data, OPJ_UINT32 p_cdef_header_size, opj_event_mgr_t * p_manager @@ -1166,15 +1320,15 @@ OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, } cdef_info = (opj_jp2_cdef_info_t*) opj_malloc(l_value * sizeof(opj_jp2_cdef_info_t)); - if (!cdef_info) - return OPJ_FALSE; + if (!cdef_info) + return OPJ_FALSE; jp2->color.jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); - if(!jp2->color.jp2_cdef) - { - opj_free(cdef_info); - return OPJ_FALSE; - } + if(!jp2->color.jp2_cdef) + { + opj_free(cdef_info); + return OPJ_FALSE; + } jp2->color.jp2_cdef->info = cdef_info; jp2->color.jp2_cdef->n = (OPJ_UINT16) l_value; @@ -1195,7 +1349,7 @@ OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, OPJ_BYTE * p_colr_header_data, OPJ_UINT32 p_colr_header_size, opj_event_mgr_t * p_manager @@ -1236,14 +1390,63 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, 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) { + if ((p_colr_header_size > 7) && (jp2->enumcs != 14)) { /* handled below for CIELab) */ /* 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 */ - - jp2->color.jp2_has_colr = 1; + + p_colr_header_data += 4; + + if(jp2->enumcs == 14)/* CIELab */ + { + OPJ_UINT32 *cielab; + OPJ_UINT32 rl, ol, ra, oa, rb, ob, il; + + cielab = (OPJ_UINT32*)opj_malloc(9 * sizeof(OPJ_UINT32)); + if(cielab == NULL){ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory for cielab\n"); + return OPJ_FALSE; + } + cielab[0] = 14; /* enumcs */ + + /* default values */ + rl = ra = rb = ol = oa = ob = 0; + il = 0x00443530; /* D50 */ + cielab[1] = 0x44454600;/* DEF */ + + if(p_colr_header_size == 35) + { + opj_read_bytes(p_colr_header_data, &rl, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &ol, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &ra, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &oa, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &rb, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &ob, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &il, 4); + p_colr_header_data += 4; + + cielab[1] = 0; + } + else if(p_colr_header_size != 7) + { + opj_event_msg(p_manager, EVT_WARNING, "Bad COLR header box (CIELab, bad size: %d)\n", p_colr_header_size); + } + cielab[2] = rl; cielab[4] = ra; cielab[6] = rb; + cielab[3] = ol; cielab[5] = oa; cielab[7] = ob; + cielab[8] = il; + + jp2->color.icc_profile_buf = (OPJ_BYTE*)cielab; + jp2->color.icc_profile_len = 0; + } + jp2->color.jp2_has_colr = 1; } else if (jp2->meth == 2) { /* ICC profile */ @@ -1252,11 +1455,11 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, jp2->color.icc_profile_len = (OPJ_UINT32)icc_len; jp2->color.icc_profile_buf = (OPJ_BYTE*) opj_calloc(1,(size_t)icc_len); - if (!jp2->color.icc_profile_buf) - { - jp2->color.icc_profile_len = 0; - return OPJ_FALSE; - } + if (!jp2->color.icc_profile_buf) + { + jp2->color.icc_profile_len = 0; + return OPJ_FALSE; + } for (it_icc_value = 0; it_icc_value < icc_len; ++it_icc_value) { @@ -1265,16 +1468,16 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, jp2->color.icc_profile_buf[it_icc_value] = (OPJ_BYTE) l_value; } - jp2->color.jp2_has_colr = 1; + jp2->color.jp2_has_colr = 1; } else if (jp2->meth > 2) - { - /* ISO/IEC 15444-1:2004 (E), Table I.9 ­ Legal METH values: - conforming JP2 reader shall ignore the entire Colour Specification box.*/ - opj_event_msg(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), " - "so we will ignore the entire Colour Specification box. \n", jp2->meth); - } - return OPJ_TRUE; + { + /* ISO/IEC 15444-1:2004 (E), Table I.9 Legal METH values: + conforming JP2 reader shall ignore the entire Colour Specification box.*/ + opj_event_msg(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), " + "so we will ignore the entire Colour Specification box. \n", jp2->meth); + } + return OPJ_TRUE; } OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, @@ -1291,52 +1494,54 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, return OPJ_FALSE; } - 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) - p_image->color_space = OPJ_CLRSPC_SRGB; - else if (jp2->enumcs == 17) - p_image->color_space = OPJ_CLRSPC_GRAY; - else if (jp2->enumcs == 18) - p_image->color_space = OPJ_CLRSPC_SYCC; - else if (jp2->enumcs == 24) - p_image->color_space = OPJ_CLRSPC_EYCC; - else - p_image->color_space = OPJ_CLRSPC_UNKNOWN; - - /* Apply the color space if needed */ - if(jp2->color.jp2_cdef) { - opj_jp2_apply_cdef(p_image, &(jp2->color)); - } - - if(jp2->color.jp2_pclr) { - /* Part 1, I.5.3.4: Either both or none : */ - if( !jp2->color.jp2_pclr->cmap) - opj_jp2_free_pclr(&(jp2->color)); - else - opj_jp2_apply_pclr(p_image, &(jp2->color)); - } - - if(jp2->color.icc_profile_buf) { - p_image->icc_profile_buf = jp2->color.icc_profile_buf; - p_image->icc_profile_len = jp2->color.icc_profile_len; - jp2->color.icc_profile_buf = NULL; - } - } + 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) + p_image->color_space = OPJ_CLRSPC_SRGB; + else if (jp2->enumcs == 17) + p_image->color_space = OPJ_CLRSPC_GRAY; + else if (jp2->enumcs == 18) + p_image->color_space = OPJ_CLRSPC_SYCC; + else if (jp2->enumcs == 24) + p_image->color_space = OPJ_CLRSPC_EYCC; + else if (jp2->enumcs == 12) + p_image->color_space = OPJ_CLRSPC_CMYK; + else + p_image->color_space = OPJ_CLRSPC_UNKNOWN; + + if(jp2->color.jp2_pclr) { + /* Part 1, I.5.3.4: Either both or none : */ + if( !jp2->color.jp2_pclr->cmap) + opj_jp2_free_pclr(&(jp2->color)); + else + opj_jp2_apply_pclr(p_image, &(jp2->color)); + } + + /* Apply the color space if needed */ + if(jp2->color.jp2_cdef) { + opj_jp2_apply_cdef(p_image, &(jp2->color), p_manager); + } + + if(jp2->color.icc_profile_buf) { + p_image->icc_profile_buf = jp2->color.icc_profile_buf; + p_image->icc_profile_len = jp2->color.icc_profile_len; + jp2->color.icc_profile_buf = NULL; + } + } return OPJ_TRUE; } -OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) { - opj_jp2_img_header_writer_handler_t l_writers [3]; + opj_jp2_img_header_writer_handler_t l_writers [4]; opj_jp2_img_header_writer_handler_t * l_current_writer; OPJ_INT32 i, l_nb_pass; @@ -1366,6 +1571,11 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, l_writers[1].handler = opj_jp2_write_colr; } + if (jp2->color.jp2_cdef != NULL) { + l_writers[l_nb_pass].handler = opj_jp2_write_cdef; + l_nb_pass++; + } + /* write box header */ /* write JP2H type */ opj_write_bytes(l_jp2h_data+4,JP2_JP2H,4); @@ -1429,12 +1639,12 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, return l_result; } -OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { OPJ_UINT32 i; - OPJ_UINT32 l_ftyp_size = 16 + 4 * jp2->numcl; + OPJ_UINT32 l_ftyp_size; OPJ_BYTE * l_ftyp_data, * l_current_data_ptr; OPJ_BOOL l_result; @@ -1442,6 +1652,7 @@ OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, assert(cio != 00); assert(jp2 != 00); assert(p_manager != 00); + l_ftyp_size = 16 + 4 * jp2->numcl; l_ftyp_data = (OPJ_BYTE *) opj_calloc(1,l_ftyp_size); @@ -1479,7 +1690,7 @@ OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, return l_result; } -OPJ_BOOL opj_jp2_write_jp2c(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_jp2c(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -1516,7 +1727,7 @@ OPJ_BOOL opj_jp2_write_jp2c(opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_write_jp( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_jp( opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -1560,17 +1771,21 @@ void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) /* JP2 encoder interface */ /* ----------------------------------------------------------------------- */ -void opj_jp2_setup_encoder( opj_jp2_t *jp2, +OPJ_BOOL opj_jp2_setup_encoder( opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t * p_manager) { - OPJ_UINT32 i; + OPJ_UINT32 i; OPJ_UINT32 depth_0; OPJ_UINT32 sign; + OPJ_UINT32 alpha_count; + OPJ_UINT32 color_channels = 0U; + OPJ_UINT32 alpha_channel = 0U; + if(!jp2 || !parameters || !image) - return; + return OPJ_FALSE; /* setup the J2K codec */ /* ------------------- */ @@ -1578,10 +1793,12 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, /* Check if number of components respects standard */ if (image->numcomps < 1 || image->numcomps > 16384) { opj_event_msg(p_manager, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); - return; + return OPJ_FALSE; } - opj_j2k_setup_encoder(jp2->j2k, parameters, image, p_manager ); + if (opj_j2k_setup_encoder(jp2->j2k, parameters, image, p_manager ) == OPJ_FALSE) { + return OPJ_FALSE; + } /* setup the JP2 codec */ /* ------------------- */ @@ -1592,22 +1809,23 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, jp2->minversion = 0; /* MinV */ jp2->numcl = 1; jp2->cl = (OPJ_UINT32*) opj_malloc(jp2->numcl * sizeof(OPJ_UINT32)); - if (!jp2->cl){ - jp2->cl = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); - return; - } + if (!jp2->cl){ + jp2->cl = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); + return OPJ_FALSE; + } jp2->cl[0] = JP2_JP2; /* CL0 : JP2 */ /* Image Header box */ jp2->numcomps = image->numcomps; /* NC */ jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); - if (!jp2->comps) { - jp2->comps = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); - return; - } + if (!jp2->comps) { + jp2->comps = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); + /* Memory of jp2->cl will be freed by opj_jp2_destroy */ + return OPJ_FALSE; + } jp2->h = image->y1 - image->y0; /* HEIGHT */ jp2->w = image->x1 - image->x0; /* WIDTH */ @@ -1645,11 +1863,81 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, jp2->enumcs = 18; /* YUV */ } + /* Channel Definition box */ + /* FIXME not provided by parameters */ + /* We try to do what we can... */ + alpha_count = 0U; + for (i = 0; i < image->numcomps; i++) { + if (image->comps[i].alpha != 0) { + alpha_count++; + alpha_channel = i; + } + } + if (alpha_count == 1U) { /* no way to deal with more than 1 alpha channel */ + switch (jp2->enumcs) { + case 16: + case 18: + color_channels = 3; + break; + case 17: + color_channels = 1; + break; + default: + alpha_count = 0U; + break; + } + if (alpha_count == 0U) { + opj_event_msg(p_manager, EVT_WARNING, "Alpha channel specified but unknown enumcs. No cdef box will be created.\n"); + } else if (image->numcomps < (color_channels+1)) { + opj_event_msg(p_manager, EVT_WARNING, "Alpha channel specified but not enough image components for an automatic cdef box creation.\n"); + alpha_count = 0U; + } else if ((OPJ_UINT32)alpha_channel < color_channels) { + opj_event_msg(p_manager, EVT_WARNING, "Alpha channel position conflicts with color channel. No cdef box will be created.\n"); + alpha_count = 0U; + } + } else if (alpha_count > 1) { + opj_event_msg(p_manager, EVT_WARNING, "Multiple alpha channels specified. No cdef box will be created.\n"); + } + if (alpha_count == 1U) { /* if here, we know what we can do */ + jp2->color.jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); + if(!jp2->color.jp2_cdef) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to setup the JP2 encoder\n"); + return OPJ_FALSE; + } + /* no memset needed, all values will be overwritten except if jp2->color.jp2_cdef->info allocation fails, */ + /* in which case jp2->color.jp2_cdef->info will be NULL => valid for destruction */ + jp2->color.jp2_cdef->info = (opj_jp2_cdef_info_t*) opj_malloc(image->numcomps * sizeof(opj_jp2_cdef_info_t)); + if (!jp2->color.jp2_cdef->info) { + /* memory will be freed by opj_jp2_destroy */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to setup the JP2 encoder\n"); + return OPJ_FALSE; + } + jp2->color.jp2_cdef->n = (OPJ_UINT16) image->numcomps; /* cast is valid : image->numcomps [1,16384] */ + for (i = 0U; i < color_channels; i++) { + jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ + jp2->color.jp2_cdef->info[i].typ = 0U; + jp2->color.jp2_cdef->info[i].asoc = (OPJ_UINT16)(i+1U); /* No overflow + cast is valid : image->numcomps [1,16384] */ + } + for (; i < image->numcomps; i++) { + if (image->comps[i].alpha != 0) { /* we'll be here exactly once */ + jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ + jp2->color.jp2_cdef->info[i].typ = 1U; /* Opacity channel */ + jp2->color.jp2_cdef->info[i].asoc = 0U; /* Apply alpha channel to the whole image */ + } else { + /* Unknown channel */ + jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ + jp2->color.jp2_cdef->info[i].typ = 65535U; + jp2->color.jp2_cdef->info[i].asoc = 65535U; + } + } + } jp2->precedence = 0; /* PRECEDENCE */ jp2->approx = 0; /* APPROX */ jp2->jpip_on = parameters->jpip_on; + + return OPJ_TRUE; } OPJ_BOOL opj_jp2_encode(opj_jp2_t *jp2, @@ -1670,7 +1958,9 @@ OPJ_BOOL opj_jp2_end_decompress(opj_jp2_t *jp2, assert(p_manager != 00); /* customization of the end encoding */ - opj_jp2_setup_end_header_reading(jp2); + if (! opj_jp2_setup_end_header_reading(jp2, p_manager)) { + return OPJ_FALSE; + } /* write header */ if (! opj_jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) { @@ -1691,7 +1981,9 @@ OPJ_BOOL opj_jp2_end_compress( opj_jp2_t *jp2, assert(p_manager != 00); /* customization of the end encoding */ - opj_jp2_setup_end_header_writing(jp2); + if (! opj_jp2_setup_end_header_writing(jp2, p_manager)) { + return OPJ_FALSE; + } if (! opj_j2k_end_compress(jp2->j2k,cio,p_manager)) { return OPJ_FALSE; @@ -1701,35 +1993,52 @@ OPJ_BOOL opj_jp2_end_compress( opj_jp2_t *jp2, return opj_jp2_exec(jp2,jp2->m_procedure_list,cio,p_manager); } -void opj_jp2_setup_end_header_writing (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_end_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); #ifdef USE_JPIP - if( jp2->jpip_on ) - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_iptr ); + if( jp2->jpip_on ) { + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_iptr, p_manager)) { + return OPJ_FALSE; + } + } #endif - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2c ); + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2c, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ #ifdef USE_JPIP if( jp2->jpip_on ) - { - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_cidx ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_fidx ); - } + { + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_cidx, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_fidx, p_manager)) { + return OPJ_FALSE; + } + } #endif + return OPJ_TRUE; } -void opj_jp2_setup_end_header_reading (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_end_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure ); + assert(p_manager != 00); + + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ + + return OPJ_TRUE; } -OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) @@ -1770,7 +2079,7 @@ OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, l_is_valid &= (jp2->w > 0); /* precision */ for (i = 0; i < jp2->numcomps; ++i) { - l_is_valid &= (jp2->comps[i].bpcc > 0); + l_is_valid &= ((jp2->comps[i].bpcc & 0x7FU) < 38U); /* 0 is valid, ignore sign for check */ } /* METH */ @@ -1783,7 +2092,7 @@ OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, return l_is_valid; } -OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) @@ -1791,6 +2100,7 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, opj_jp2_box_t box; OPJ_UINT32 l_nb_bytes_read; const opj_jp2_header_handler_t * l_current_handler; + const opj_jp2_header_handler_t * l_current_handler_misplaced; OPJ_UINT32 l_last_data_size = OPJ_BOX_SIZE; OPJ_UINT32 l_current_data_size; OPJ_BYTE * l_current_data = 00; @@ -1812,7 +2122,7 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, if (box.type == JP2_JP2C) { if (jp2->jp2_state & JP2_STATE_HEADER) { jp2->jp2_state |= JP2_STATE_CODESTREAM; - opj_free(l_current_data); + opj_free(l_current_data); return OPJ_TRUE; } else { @@ -1827,16 +2137,39 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, return OPJ_FALSE; } /* testcase 1851.pdf.SIGSEGV.ce9.948 */ - else if (box.length < l_nb_bytes_read) { + else if (box.length < l_nb_bytes_read) { opj_event_msg(p_manager, EVT_ERROR, "invalid box size %d (%x)\n", box.length, box.type); opj_free(l_current_data); return OPJ_FALSE; } l_current_handler = opj_jp2_find_handler(box.type); + l_current_handler_misplaced = opj_jp2_img_find_handler(box.type); l_current_data_size = box.length - l_nb_bytes_read; - if (l_current_handler != 00) { + if ((l_current_handler != 00) || (l_current_handler_misplaced != 00)) { + if (l_current_handler == 00) { + opj_event_msg(p_manager, EVT_WARNING, "Found a misplaced '%c%c%c%c' box outside jp2h box\n", (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0)); + if (jp2->jp2_state & JP2_STATE_HEADER) { + /* read anyway, we already have jp2h */ + l_current_handler = l_current_handler_misplaced; + } else { + opj_event_msg(p_manager, EVT_WARNING, "JPEG2000 Header box not read yet, '%c%c%c%c' box will be ignored\n", (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0)); + jp2->jp2_state |= JP2_STATE_UNKNOWN; + if (opj_stream_skip(stream,l_current_data_size,p_manager) != l_current_data_size) { + opj_event_msg(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + continue; + } + } + if ((OPJ_OFF_T)l_current_data_size > opj_stream_get_number_byte_left(stream)) { + /* do not even try to malloc if we can't read */ + opj_event_msg(p_manager, EVT_ERROR, "Invalid box size %d for box '%c%c%c%c'. Need %d bytes, %d bytes remaining \n", box.length, (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0), l_current_data_size, (OPJ_UINT32)opj_stream_get_number_byte_left(stream)); + opj_free(l_current_data); + return OPJ_FALSE; + } if (l_current_data_size > l_last_data_size) { OPJ_BYTE* new_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_data_size); if (!new_current_data) { @@ -1861,6 +2194,16 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, } } else { + if (!(jp2->jp2_state & JP2_STATE_SIGNATURE)) { + opj_event_msg(p_manager, EVT_ERROR, "Malformed JP2 file format: first box must be JPEG 2000 signature box\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + if (!(jp2->jp2_state & JP2_STATE_FILE_TYPE)) { + opj_event_msg(p_manager, EVT_ERROR, "Malformed JP2 file format: second box must be file type box\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } jp2->jp2_state |= JP2_STATE_UNKNOWN; if (opj_stream_skip(stream,l_current_data_size,p_manager) != l_current_data_size) { opj_event_msg(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); @@ -1927,7 +2270,9 @@ OPJ_BOOL opj_jp2_start_compress(opj_jp2_t *jp2, assert(p_manager != 00); /* customization of the validation */ - opj_jp2_setup_encoding_validation (jp2); + if (! opj_jp2_setup_encoding_validation (jp2, p_manager)) { + return OPJ_FALSE; + } /* validation of the parameters codec */ if (! opj_jp2_exec(jp2,jp2->m_validation_list,stream,p_manager)) { @@ -1935,7 +2280,9 @@ OPJ_BOOL opj_jp2_start_compress(opj_jp2_t *jp2, } /* customization of the encoding */ - opj_jp2_setup_header_writing(jp2); + if (! opj_jp2_setup_header_writing(jp2, p_manager)) { + return OPJ_FALSE; + } /* write header */ if (! opj_jp2_exec (jp2,jp2->m_procedure_list,stream,p_manager)) { @@ -1945,7 +2292,7 @@ OPJ_BOOL opj_jp2_start_compress(opj_jp2_t *jp2, return opj_j2k_start_compress(jp2->j2k,stream,p_image,p_manager); } -const opj_jp2_header_handler_t * opj_jp2_find_handler (OPJ_UINT32 p_id) +static const opj_jp2_header_handler_t * opj_jp2_find_handler (OPJ_UINT32 p_id) { OPJ_UINT32 i, l_handler_size = sizeof(jp2_header) / sizeof(opj_jp2_header_handler_t); @@ -2093,7 +2440,7 @@ static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) { @@ -2137,7 +2484,7 @@ static OPJ_BOOL opj_jpip_skip_iptr( opj_jp2_t *jp2, * @param p_header_size the size of the data contained in the file header box. * @param p_manager the user event manager. * - * @return true if the JP2 Header box was successfully reconized. + * @return true if the JP2 Header box was successfully recognized. */ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, OPJ_BYTE *p_header_data, @@ -2148,6 +2495,7 @@ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, OPJ_UINT32 l_box_size=0, l_current_data_size = 0; opj_jp2_box_t box; const opj_jp2_header_handler_t * l_current_handler; + OPJ_BOOL l_has_ihdr = 0; /* preconditions */ assert(p_header_data != 00); @@ -2188,16 +2536,25 @@ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, jp2->jp2_img_state |= JP2_IMG_STATE_UNKNOWN; } + if (box.type == JP2_IHDR) { + l_has_ihdr = 1; + } + p_header_data += l_current_data_size; p_header_size -= box.length; } + if (l_has_ihdr == 0) { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box: no 'ihdr' box.\n"); + return OPJ_FALSE; + } + jp2->jp2_state |= JP2_STATE_HEADER; return OPJ_TRUE; } -OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, +static OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, OPJ_BYTE * p_data, OPJ_UINT32 * p_number_bytes_read, OPJ_UINT32 p_box_max_size, @@ -2260,7 +2617,10 @@ OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); return OPJ_FALSE; } - + if (box->length < *p_number_bytes_read) { + opj_event_msg(p_manager, EVT_ERROR, "Box length is inconsistent.\n"); + return OPJ_FALSE; + } return OPJ_TRUE; } @@ -2276,10 +2636,14 @@ OPJ_BOOL opj_jp2_read_header( opj_stream_private_t *p_stream, assert(p_manager != 00); /* customization of the validation */ - opj_jp2_setup_decoding_validation (jp2); + if (! opj_jp2_setup_decoding_validation (jp2, p_manager)) { + return OPJ_FALSE; + } /* customization of the encoding */ - opj_jp2_setup_header_reading(jp2); + if (! opj_jp2_setup_header_reading(jp2, p_manager)) { + return OPJ_FALSE; + } /* validation of the parameters codec */ if (! opj_jp2_exec(jp2,jp2->m_validation_list,p_stream,p_manager)) { @@ -2297,45 +2661,73 @@ OPJ_BOOL opj_jp2_read_header( opj_stream_private_t *p_stream, p_manager); } -void opj_jp2_setup_encoding_validation (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_encoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(jp2->m_validation_list, (opj_procedure)opj_jp2_default_validation); + if (! opj_procedure_list_add_procedure(jp2->m_validation_list, (opj_procedure)opj_jp2_default_validation, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom validation procedure */ + + return OPJ_TRUE; } -void opj_jp2_setup_decoding_validation (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_decoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); + /* DEVELOPER CORNER, add your custom validation procedure */ + + return OPJ_TRUE; } -void opj_jp2_setup_header_writing (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_ftyp ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2h ); - if( jp2->jpip_on ) - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_skip_iptr ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_skip_jp2c ); + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_ftyp, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2h, p_manager)) { + return OPJ_FALSE; + } + if( jp2->jpip_on ) { + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_skip_iptr, p_manager)) { + return OPJ_FALSE; + } + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_skip_jp2c,p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, insert your custom procedures */ + return OPJ_TRUE; } -void opj_jp2_setup_header_reading (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure ); + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure, p_manager)) { + return OPJ_FALSE; + } + /* DEVELOPER CORNER, add your custom procedures */ + + return OPJ_TRUE; } OPJ_BOOL opj_jp2_read_tile_header ( opj_jp2_t * p_jp2, @@ -2491,14 +2883,13 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, p_image->color_space = OPJ_CLRSPC_GRAY; else if (p_jp2->enumcs == 18) p_image->color_space = OPJ_CLRSPC_SYCC; + else if (p_jp2->enumcs == 24) + p_image->color_space = OPJ_CLRSPC_EYCC; + else if (p_jp2->enumcs == 12) + p_image->color_space = OPJ_CLRSPC_CMYK; else p_image->color_space = OPJ_CLRSPC_UNKNOWN; - /* Apply the color space if needed */ - if(p_jp2->color.jp2_cdef) { - opj_jp2_apply_cdef(p_image, &(p_jp2->color)); - } - if(p_jp2->color.jp2_pclr) { /* Part 1, I.5.3.4: Either both or none : */ if( !p_jp2->color.jp2_pclr->cmap) @@ -2506,6 +2897,11 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, else opj_jp2_apply_pclr(p_image, &(p_jp2->color)); } + + /* Apply the color space if needed */ + if(p_jp2->color.jp2_cdef) { + opj_jp2_apply_cdef(p_image, &(p_jp2->color), p_manager); + } if(p_jp2->color.icc_profile_buf) { p_image->icc_profile_buf = p_jp2->color.icc_profile_buf;