X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fopenjp2%2Fjp2.c;h=c14e9a066726673b18cab8d989f95188b377a06a;hb=26b2728c493d30c2ecc058e775cbc8c86c158e88;hp=9b7caa4ee750b470ede9b30f294e7c048f0a6337;hpb=482d9b58b329ad8e7fe746a373603071dba4bfb9;p=openjpeg.git diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index 9b7caa4e..c14e9a06 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -1,11 +1,19 @@ /* - * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium - * Copyright (c) 2002-2007, Professor Benoit Macq + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq * Copyright (c) 2001-2003, David Janssens * Copyright (c) 2002-2003, Yannick Verschueren - * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2010-2011, Kaori Hagihara + * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR + * Copyright (c) 2012, CS Systemes d'Information, France * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +42,7 @@ /** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ /*@{*/ -#define BOX_SIZE 1024 +#define OPJ_BOX_SIZE 1024 /** @name Local static functions */ /*@{*/ @@ -51,7 +59,7 @@ * * @return true if the image header is valid, false else. */ -static 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 ); @@ -88,17 +96,28 @@ static OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, * * @return true if the bpc header is valid, fale else. */ -static 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 ); -static 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 ); -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. @@ -120,7 +139,7 @@ static OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, * * @return true if writing was successful. */ -static 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 ); @@ -134,12 +153,12 @@ static opj_bool opj_jp2_write_ftyp( opj_jp2_t *jp2, * * @return true if the FTYP box is valid. */ -static opj_bool opj_jp2_read_ftyp( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, OPJ_BYTE * p_header_data, 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 ); @@ -151,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, +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. * @@ -167,7 +199,7 @@ static opj_bool opj_jp2_read_jp2h( opj_jp2_t *jp2, * * @return true if writing was successful. */ -static 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 ); @@ -178,7 +210,7 @@ static opj_bool opj_jp2_write_jp2c( opj_jp2_t *jp2, * @param jp2 the jpeg2000 file codec. * @param p_manager user event manager. */ -static opj_bool opj_jpip_write_iptr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_write_iptr( opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); @@ -188,7 +220,7 @@ static opj_bool opj_jpip_write_iptr( opj_jp2_t *jp2, * @param jp2 the jpeg2000 file codec. * @param p_manager user event manager. */ -static opj_bool opj_jpip_write_cidx(opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_write_cidx(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); @@ -198,7 +230,7 @@ static opj_bool opj_jpip_write_cidx(opj_jp2_t *jp2, * @param jp2 the jpeg2000 file codec. * @param p_manager user event manager. */ -static opj_bool opj_jpip_write_fidx(opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_write_fidx(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); #endif /* USE_JPIP */ @@ -213,7 +245,7 @@ static opj_bool opj_jpip_write_fidx(opj_jp2_t *jp2, * * @return true if the file signature box is valid. */ -static opj_bool opj_jp2_read_jp(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_jp(opj_jp2_t *jp2, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager); @@ -227,7 +259,7 @@ static opj_bool opj_jp2_read_jp(opj_jp2_t *jp2, * * @return true if writing was successful. */ -static 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 ); @@ -250,7 +282,7 @@ static void opj_jp2_free_pclr(opj_jp2_color_t *color); * * @return Returns true if successful, returns false otherwise */ -static 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 ); @@ -266,7 +298,7 @@ static opj_bool opj_jp2_read_pclr( opj_jp2_t *jp2, * @return Returns true if successful, returns false otherwise */ -static 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 ); @@ -281,7 +313,7 @@ static opj_bool opj_jp2_read_cmap( opj_jp2_t * jp2, * * @return true if the bpc header is valid, fale else. */ -static 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 ); @@ -294,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. @@ -311,7 +343,7 @@ static void opj_jp2_setup_end_header_reading (opj_jp2_t *jp2); * * @return true if the box is valid. */ -static 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 ); @@ -325,7 +357,7 @@ static opj_bool opj_jp2_read_header_procedure( opj_jp2_t *jp2, * * @return true if all the procedures were successfully executed. */ -static opj_bool opj_jp2_exec ( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_exec ( opj_jp2_t * jp2, opj_procedure_list_t * p_procedure_list, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ); @@ -338,9 +370,9 @@ 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, +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); @@ -349,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 ); @@ -378,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}, @@ -405,9 +437,9 @@ 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, +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, @@ -417,21 +449,19 @@ 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, - OPJ_UINT32 * p_number_bytes_read, - opj_stream_private_t *cio, - opj_event_mgr_t * p_manager - ) +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 ) { /* read header from file */ OPJ_BYTE l_data_header [8]; @@ -442,7 +472,7 @@ static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); assert(p_number_bytes_read != 00); assert(p_manager != 00); - *p_number_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + *p_number_bytes_read = (OPJ_UINT32)opj_stream_read_data(cio,l_data_header,8,p_manager); if (*p_number_bytes_read != 8) { return OPJ_FALSE; } @@ -450,13 +480,21 @@ static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); /* process read data */ opj_read_bytes(l_data_header,&(box->length), 4); 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; + } /* do we have a "special very large box ?" */ /* read then the XLBox */ if (box->length == 1) { OPJ_UINT32 l_xl_part_size; - OPJ_UINT32 l_nb_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + OPJ_UINT32 l_nb_bytes_read = (OPJ_UINT32)opj_stream_read_data(cio,l_data_header,8,p_manager); if (l_nb_bytes_read != 8) { if (l_nb_bytes_read > 0) { *p_number_bytes_read += l_nb_bytes_read; @@ -465,14 +503,15 @@ static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); return OPJ_FALSE; } + *p_number_bytes_read = 16; opj_read_bytes(l_data_header,&l_xl_part_size, 4); if (l_xl_part_size != 0) { opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); return OPJ_FALSE; } - opj_read_bytes(l_data_header,&(box->length), 4); + opj_read_bytes(l_data_header+4,&(box->length), 4); } - return OPJ_TRUE; + return OPJ_TRUE; } #if 0 @@ -499,7 +538,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 ) @@ -522,12 +561,11 @@ opj_bool opj_jp2_read_ihdr( opj_jp2_t *jp2, p_image_header_data += 2; /* allocate memory for components */ - jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + jp2->comps = (opj_jp2_comps_t*) opj_calloc(jp2->numcomps, sizeof(opj_jp2_comps_t)); if (jp2->comps == 0) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle image header (ihdr)\n"); return OPJ_FALSE; } - memset(jp2->comps,0,jp2->numcomps * sizeof(opj_jp2_comps_t)); opj_read_bytes(p_image_header_data,&(jp2->bpc),1); /* BPC */ ++ p_image_header_data; @@ -548,7 +586,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 ) { @@ -559,11 +597,10 @@ OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, assert(p_nb_bytes_written != 00); /* default image header is 22 bytes wide */ - l_ihdr_data = (OPJ_BYTE *) opj_malloc(22); + l_ihdr_data = (OPJ_BYTE *) opj_calloc(1,22); if (l_ihdr_data == 00) { return 00; } - memset(l_ihdr_data,0,22); l_current_ihdr_ptr = l_ihdr_data; @@ -599,24 +636,23 @@ 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_INT32 l_bpcc_size = 8 + jp2->numcomps; + OPJ_UINT32 l_bpcc_size = 8 + jp2->numcomps; OPJ_BYTE * l_bpcc_data,* l_current_bpcc_ptr; /* preconditions */ assert(jp2 != 00); assert(p_nb_bytes_written != 00); - l_bpcc_data = (OPJ_BYTE *) opj_malloc(l_bpcc_size); + l_bpcc_data = (OPJ_BYTE *) opj_calloc(1,l_bpcc_size); if (l_bpcc_data == 00) { return 00; } - memset(l_bpcc_data,0,l_bpcc_size); l_current_bpcc_ptr = l_bpcc_data; @@ -636,7 +672,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 @@ -668,35 +704,85 @@ 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); + assert(jp2->meth == 1 || jp2->meth == 2); - switch (jp2->meth) { + switch (jp2->meth) { case 1 : - l_colr_size += 4; + l_colr_size += 4; /* EnumCS */ break; case 2 : - ++l_colr_size; + assert(jp2->color.icc_profile_len); /* ICC profile */ + l_colr_size += jp2->color.icc_profile_len; break; default : return 00; } - l_colr_data = (OPJ_BYTE *) opj_malloc(l_colr_size); + l_colr_data = (OPJ_BYTE *) opj_calloc(1,l_colr_size); if (l_colr_data == 00) { return 00; } - memset(l_colr_data,0,l_colr_size); l_current_colr_ptr = l_colr_data; @@ -715,11 +801,16 @@ OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, opj_write_bytes(l_current_colr_ptr, jp2->approx,1); /* APPROX */ ++l_current_colr_ptr; - if (jp2->meth == 1) { - opj_write_bytes(l_current_colr_ptr, jp2->enumcs,4); /* EnumCS */ - } - else { - opj_write_bytes(l_current_colr_ptr, 0, 1); /* PROFILE (??) */ + if (jp2->meth == 1) { /* Meth value is restricted to 1 or 2 (Table I.9 of part 1) */ + opj_write_bytes(l_current_colr_ptr, jp2->enumcs,4); } /* EnumCS */ + else { + if (jp2->meth == 2) { /* ICC profile */ + OPJ_UINT32 i; + for(i = 0; i < jp2->color.icc_profile_len; ++i) { + opj_write_bytes(l_current_colr_ptr, jp2->color.icc_profile_buf[i], 1); + ++l_current_colr_ptr; + } + } } *p_nb_bytes_written = l_colr_size; @@ -727,7 +818,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); @@ -738,7 +829,127 @@ void opj_jp2_free_pclr(opj_jp2_color_t *color) opj_free(color->jp2_pclr); color->jp2_pclr = NULL; } -void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) +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; + 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 >= 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 == 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 + 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_BOOL *) 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; + assert(cmap[i].mtyp == 0 || cmap[i].mtyp == 1); + 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] && cmap[i].mtyp == 1) { + opj_event_msg(p_manager, EVT_ERROR, "Component %d is mapped twice.\n", pcol); + is_sane = OPJ_FALSE; + } + else if (cmap[i].mtyp == 0 && cmap[i].pcol != 0) { + /* I.5.3.5 PCOL: If the value of the MTYP field for this channel is 0, then + * the value of this field shall be 0. */ + opj_event_msg(p_manager, EVT_ERROR, "Direct use at #%d however pcol=%d.\n", i, 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] && cmap[i].mtyp != 0) { + opj_event_msg(p_manager, EVT_ERROR, "Component %d doesn't have a mapping.\n", i); + 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; + } + } + + return OPJ_TRUE; +} + +/* file9.jp2 */ +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; @@ -758,44 +969,67 @@ 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; - new_comps[pcol] = old_comps[cmp]; - /* Direct use */ - if(cmap[i].mtyp == 0){ - old_comps[cmp].data = NULL; continue; - } + if(cmap[i].mtyp == 0){ + assert( pcol == 0 ); + new_comps[i] = old_comps[cmp]; + } else { + assert( i == pcol ); + new_comps[pcol] = old_comps[cmp]; + } /* Palette mapping: */ - new_comps[pcol].data = (OPJ_INT32*) + new_comps[i].data = (OPJ_INT32*) opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(OPJ_INT32)); - new_comps[pcol].prec = channel_size[i]; - new_comps[pcol].sgnd = channel_sign[i]; + 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]; } top_k = color->jp2_pclr->nr_entries - 1; for(i = 0; i < nr_channels; ++i) { - /* Direct use: */ - if(cmap[i].mtyp == 0) continue; - /* Palette mapping: */ cmp = cmap[i].cmp; pcol = cmap[i].pcol; src = old_comps[cmp].data; - dst = new_comps[pcol].data; + assert( src ); max = new_comps[pcol].w * new_comps[pcol].h; - for(j = 0; j < max; ++j) - { - /* The index */ - if((k = src[j]) < 0) k = 0; else if(k > top_k) k = top_k; - - /* The colour */ - dst[j] = entries[k * nr_channels + pcol]; - } + /* Direct use: */ + if(cmap[i].mtyp == 0) { + assert( cmp == 0 ); + dst = new_comps[i].data; + assert( dst ); + for(j = 0; j < max; ++j) { + dst[j] = src[j]; + } + } + else { + assert( i == pcol ); + dst = new_comps[pcol].data; + assert( dst ); + for(j = 0; j < max; ++j) { + /* The index */ + if((k = src[j]) < 0) k = 0; else if(k > top_k) k = top_k; + + /* The colour */ + dst[j] = (OPJ_INT32)entries[k * nr_channels + pcol]; + } + } } max = image->numcomps; @@ -811,7 +1045,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 @@ -823,6 +1057,7 @@ opj_bool opj_jp2_read_pclr( opj_jp2_t *jp2, OPJ_UINT16 nr_entries,nr_channels; OPJ_UINT16 i, j; OPJ_UINT32 l_value; + OPJ_BYTE *orig_header_data = p_pclr_header_data; /* preconditions */ assert(p_pclr_header_data != 00); @@ -833,19 +1068,54 @@ opj_bool opj_jp2_read_pclr( opj_jp2_t *jp2, if(jp2->color.jp2_pclr) return OPJ_FALSE; + if (p_pclr_header_size < 3) + return OPJ_FALSE; + 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; + } - entries = (OPJ_UINT32*) opj_malloc(nr_channels * nr_entries * sizeof(OPJ_UINT32)); + 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)); + if (!entries) + return OPJ_FALSE; channel_size = (OPJ_BYTE*) opj_malloc(nr_channels); + if (!channel_size) + { + opj_free(entries); + return OPJ_FALSE; + } channel_sign = (OPJ_BYTE*) opj_malloc(nr_channels); + if (!channel_sign) + { + opj_free(entries); + opj_free(channel_size); + return OPJ_FALSE; + } jp2_pclr = (opj_jp2_pclr_t*)opj_malloc(sizeof(opj_jp2_pclr_t)); + if (!jp2_pclr) + { + opj_free(entries); + opj_free(channel_size); + opj_free(channel_sign); + return OPJ_FALSE; + } + jp2_pclr->channel_sign = channel_sign; jp2_pclr->channel_size = channel_size; jp2_pclr->entries = entries; @@ -859,13 +1129,18 @@ opj_bool opj_jp2_read_pclr( opj_jp2_t *jp2, opj_read_bytes(p_pclr_header_data, &l_value , 1); /* Bi */ ++p_pclr_header_data; - channel_size[i] = (l_value & 0x7f) + 1; - channel_sign[i] = (l_value & 0x80)? 1 : 0; + channel_size[i] = (OPJ_BYTE)((l_value & 0x7f) + 1); + channel_sign[i] = (l_value & 0x80) ? 1 : 0; } for(j = 0; j < nr_entries; ++j) { for(i = 0; i < nr_channels; ++i) { - OPJ_INT32 bytes_to_read = (channel_size[i]+7)>>3; + OPJ_UINT32 bytes_to_read = (OPJ_UINT32)((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 < (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 */ p_pclr_header_data += bytes_to_read; @@ -877,7 +1152,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 @@ -891,7 +1166,7 @@ opj_bool opj_jp2_read_cmap( opj_jp2_t * jp2, assert(jp2 != 00); assert(p_cmap_header_data != 00); assert(p_manager != 00); - (void)p_cmap_header_size; + (void)p_cmap_header_size; /* Need nr_channels: */ if(jp2->color.jp2_pclr == NULL) { @@ -908,7 +1183,15 @@ opj_bool opj_jp2_read_cmap( opj_jp2_t * jp2, } nr_channels = jp2->color.jp2_pclr->nr_channels; + 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; + for(i = 0; i < nr_channels; ++i) { opj_read_bytes(p_cmap_header_data, &l_value, 2); /* CMP^i */ @@ -929,42 +1212,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 ! */ - if((asoc = info[i].asoc) == 0) continue; - - cn = info[i].cn; - acn = asoc - 1; - - if(cn != acn) + 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 = cn + 1; - info[acn].asoc = 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 @@ -984,6 +1296,11 @@ opj_bool opj_jp2_read_cdef( opj_jp2_t * jp2, * inside a JP2 Header box.'*/ if(jp2->color.jp2_cdef) 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; @@ -992,9 +1309,21 @@ 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; 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; + } jp2->color.jp2_cdef->info = cdef_info; jp2->color.jp2_cdef->n = (OPJ_UINT16) l_value; @@ -1015,7 +1344,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 @@ -1052,22 +1381,76 @@ 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) && (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 */ + + 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)); + 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 */ OPJ_INT32 it_icc_value = 0; - OPJ_INT32 icc_len = p_colr_header_size - 3; - - jp2->color.icc_profile_len = icc_len; - jp2->color.icc_profile_buf = (OPJ_BYTE*) opj_malloc(icc_len); + OPJ_INT32 icc_len = (OPJ_INT32)p_colr_header_size - 3; - memset(jp2->color.icc_profile_buf, 0, icc_len * sizeof(OPJ_BYTE)); + 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; + } for (it_icc_value = 0; it_icc_value < icc_len; ++it_icc_value) { @@ -1075,17 +1458,20 @@ opj_bool opj_jp2_read_colr( opj_jp2_t *jp2, ++p_colr_header_data; jp2->color.icc_profile_buf[it_icc_value] = (OPJ_BYTE) l_value; } - + + 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); } - else - opj_event_msg(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), so we will skip the fields following the approx field.\n", jp2->meth); - - jp2->color.jp2_has_colr = 1; - return OPJ_TRUE; } -opj_bool opj_jp2_decode(opj_jp2_t *jp2, +OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, opj_stream_private_t *p_stream, opj_image_t* p_image, opj_event_mgr_t * p_manager) @@ -1099,53 +1485,60 @@ opj_bool opj_jp2_decode(opj_jp2_t *jp2, return OPJ_FALSE; } - if (!jp2->ignore_pclr_cmap_cdef){ - - /* Set Image Color Space */ - if (jp2->enumcs == 16) - p_image->color_space = CLRSPC_SRGB; - else if (jp2->enumcs == 17) - p_image->color_space = CLRSPC_GRAY; - else if (jp2->enumcs == 18) - p_image->color_space = CLRSPC_SYCC; - else - p_image->color_space = 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; /* size of data for super box*/ - OPJ_INT32 l_jp2h_size = 8; - opj_bool l_result = OPJ_TRUE; + OPJ_UINT32 l_jp2h_size = 8; + OPJ_BOOL l_result = OPJ_TRUE; /* to store the data of the super box */ OPJ_BYTE l_jp2h_data [8]; @@ -1169,6 +1562,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); @@ -1232,29 +1630,27 @@ 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_BYTE * l_ftyp_data, * l_current_data_ptr; - opj_bool l_result; + OPJ_BOOL l_result; /* preconditions */ assert(cio != 00); assert(jp2 != 00); assert(p_manager != 00); - l_ftyp_data = (OPJ_BYTE *) opj_malloc(l_ftyp_size); + l_ftyp_data = (OPJ_BYTE *) opj_calloc(1,l_ftyp_size); if (l_ftyp_data == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle ftyp data\n"); return OPJ_FALSE; } - memset(l_ftyp_data,0,l_ftyp_size); - l_current_data_ptr = l_ftyp_data; opj_write_bytes(l_current_data_ptr, l_ftyp_size,4); /* box size */ @@ -1284,7 +1680,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 ) { @@ -1321,7 +1717,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 ) { @@ -1365,16 +1761,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_INT32 depth_0, sign; + 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 */ /* ------------------- */ @@ -1382,10 +1783,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 */ /* ------------------- */ @@ -1396,12 +1799,24 @@ 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 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"); + /* 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 */ /* BPC */ @@ -1409,7 +1824,7 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, sign = image->comps[0].sgnd; jp2->bpc = depth_0 + (sign << 7); for (i = 1; i < image->numcomps; i++) { - OPJ_INT32 depth = image->comps[i].prec - 1; + OPJ_UINT32 depth = image->comps[i].prec - 1; sign = image->comps[i].sgnd; if (depth_0 != depth) jp2->bpc = 255; @@ -1424,35 +1839,105 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, } /* Colour Specification box */ - if ((image->numcomps == 1 || image->numcomps == 3) && (jp2->bpc != 255)) { - jp2->meth = 1; /* METH: Enumerated colourspace */ - } else { - jp2->meth = 2; /* METH: Restricted ICC profile */ + if(image->icc_profile_len) { + jp2->meth = 2; + jp2->enumcs = 0; + } + else { + jp2->meth = 1; + if (image->color_space == 1) + jp2->enumcs = 16; /* sRGB as defined by IEC 61966-2-1 */ + else if (image->color_space == 2) + jp2->enumcs = 17; /* greyscale */ + else if (image->color_space == 3) + 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 (jp2->meth == 1) { - if (image->color_space == 1) - jp2->enumcs = 16; /* sRGB as defined by IEC 61966-2-1 */ - else if (image->color_space == 2) - jp2->enumcs = 17; /* greyscale */ - else if (image->color_space == 3) - jp2->enumcs = 18; /* YUV */ - } else { - jp2->enumcs = 0; /* PROFILE (??) */ + 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, +OPJ_BOOL opj_jp2_encode(opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager) { - return opj_j2k_encode_v2(jp2->j2k, stream, p_manager); + return opj_j2k_encode(jp2->j2k, stream, p_manager); } -opj_bool opj_jp2_end_decompress(opj_jp2_t *jp2, +OPJ_BOOL opj_jp2_end_decompress(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) @@ -1463,7 +1948,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)) { @@ -1473,7 +1960,7 @@ opj_bool opj_jp2_end_decompress(opj_jp2_t *jp2, return opj_j2k_end_decompress(jp2->j2k, cio, p_manager); } -opj_bool opj_jp2_end_compress( opj_jp2_t *jp2, +OPJ_BOOL opj_jp2_end_compress( opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) @@ -1484,7 +1971,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; @@ -1494,40 +1983,57 @@ 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 ) { - opj_bool l_is_valid = OPJ_TRUE; + OPJ_BOOL l_is_valid = OPJ_TRUE; OPJ_UINT32 i; /* preconditions */ @@ -1563,7 +2069,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 */ @@ -1576,7 +2082,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 ) @@ -1584,7 +2090,8 @@ 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; - OPJ_UINT32 l_last_data_size = BOX_SIZE; + 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; @@ -1593,13 +2100,12 @@ opj_bool opj_jp2_read_header_procedure( opj_jp2_t *jp2, assert(jp2 != 00); assert(p_manager != 00); - l_current_data = (OPJ_BYTE*)opj_malloc(l_last_data_size); + l_current_data = (OPJ_BYTE*)opj_calloc(1,l_last_data_size); if (l_current_data == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle jpeg2000 file header\n"); return OPJ_FALSE; } - memset(l_current_data, 0 , l_last_data_size); while (opj_jp2_read_boxhdr(&box,&l_nb_bytes_read,stream,p_manager)) { /* is it the codestream box ? */ @@ -1620,14 +2126,43 @@ opj_bool opj_jp2_read_header_procedure( opj_jp2_t *jp2, opj_free(l_current_data); return OPJ_FALSE; } + /* testcase 1851.pdf.SIGSEGV.ce9.948 */ + 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 (!l_current_data){ + if (!new_current_data) { opj_free(l_current_data); opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle jpeg2000 box\n"); return OPJ_FALSE; @@ -1636,7 +2171,7 @@ opj_bool opj_jp2_read_header_procedure( opj_jp2_t *jp2, l_last_data_size = l_current_data_size; } - l_nb_bytes_read = opj_stream_read_data(stream,l_current_data,l_current_data_size,p_manager); + l_nb_bytes_read = (OPJ_UINT32)opj_stream_read_data(stream,l_current_data,l_current_data_size,p_manager); if (l_nb_bytes_read != l_current_data_size) { opj_event_msg(p_manager, EVT_ERROR, "Problem with reading JPEG2000 box, stream error\n"); opj_free(l_current_data); @@ -1649,6 +2184,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"); @@ -1673,15 +2218,15 @@ opj_bool opj_jp2_read_header_procedure( opj_jp2_t *jp2, * * @return true if all the procedures were successfully executed. */ -static opj_bool opj_jp2_exec ( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_exec ( opj_jp2_t * jp2, opj_procedure_list_t * p_procedure_list, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) { - opj_bool (** l_procedure) (opj_jp2_t * jp2, opj_stream_private_t *, opj_event_mgr_t *) = 00; - opj_bool l_result = OPJ_TRUE; + OPJ_BOOL (** l_procedure) (opj_jp2_t * jp2, opj_stream_private_t *, opj_event_mgr_t *) = 00; + OPJ_BOOL l_result = OPJ_TRUE; OPJ_UINT32 l_nb_proc, i; /* preconditions */ @@ -1691,7 +2236,7 @@ static opj_bool opj_jp2_exec ( opj_jp2_t * jp2, assert(p_manager != 00); l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); - l_procedure = (opj_bool (**) (opj_jp2_t * jp2, opj_stream_private_t *, opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + l_procedure = (OPJ_BOOL (**) (opj_jp2_t * jp2, opj_stream_private_t *, opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); for (i=0;im_validation_list,stream,p_manager)) { @@ -1723,7 +2270,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)) { @@ -1733,7 +2282,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); @@ -1775,7 +2324,7 @@ static const opj_jp2_header_handler_t * opj_jp2_img_find_handler (OPJ_UINT32 p_i * * @return true if the file signature box is valid. */ -static opj_bool opj_jp2_read_jp(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_jp(opj_jp2_t *jp2, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager @@ -1822,7 +2371,7 @@ static opj_bool opj_jp2_read_jp(opj_jp2_t *jp2, * * @return true if the FTYP box is valid. */ -static opj_bool opj_jp2_read_ftyp( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager @@ -1863,12 +2412,11 @@ static opj_bool opj_jp2_read_ftyp( opj_jp2_t *jp2, /* div by 4 */ jp2->numcl = l_remaining_bytes >> 2; if (jp2->numcl) { - jp2->cl = (OPJ_UINT32 *) opj_malloc(jp2->numcl * sizeof(OPJ_UINT32)); + jp2->cl = (OPJ_UINT32 *) opj_calloc(jp2->numcl, sizeof(OPJ_UINT32)); if (jp2->cl == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory with FTYP Box\n"); return OPJ_FALSE; } - memset(jp2->cl,0,jp2->numcl * sizeof(OPJ_UINT32)); } for (i = 0; i < jp2->numcl; ++i) @@ -1882,7 +2430,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 ) { @@ -1900,7 +2448,7 @@ opj_bool opj_jp2_skip_jp2c( opj_jp2_t *jp2, return OPJ_TRUE; } -static opj_bool opj_jpip_skip_iptr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_skip_iptr( opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) { @@ -1926,9 +2474,9 @@ 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, +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 @@ -1937,6 +2485,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); @@ -1977,16 +2526,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, @@ -2009,11 +2567,11 @@ opj_bool opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, /* process read data */ opj_read_bytes(p_data, &l_value, 4); p_data += 4; - box->length = (OPJ_INT32)(l_value); + box->length = (OPJ_UINT32)(l_value); opj_read_bytes(p_data, &l_value, 4); p_data += 4; - box->type = (OPJ_INT32)(l_value); + box->type = (OPJ_UINT32)(l_value); *p_number_bytes_read = 8; @@ -2038,7 +2596,7 @@ opj_bool opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, opj_read_bytes(p_data, &l_value, 4); *p_number_bytes_read += 4; - box->length = (OPJ_INT32)(l_value); + box->length = (OPJ_UINT32)(l_value); if (box->length == 0) { opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); @@ -2049,11 +2607,14 @@ 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; } -opj_bool opj_jp2_read_header( opj_stream_private_t *p_stream, +OPJ_BOOL opj_jp2_read_header( opj_stream_private_t *p_stream, opj_jp2_t *jp2, opj_image_t ** p_image, opj_event_mgr_t * p_manager @@ -2065,10 +2626,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)) { @@ -2086,48 +2651,76 @@ 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, +OPJ_BOOL opj_jp2_read_tile_header ( opj_jp2_t * p_jp2, OPJ_UINT32 * p_tile_index, OPJ_UINT32 * p_data_size, OPJ_INT32 * p_tile_x0, @@ -2135,7 +2728,7 @@ opj_bool opj_jp2_read_tile_header ( opj_jp2_t * p_jp2, OPJ_INT32 * p_tile_x1, OPJ_INT32 * p_tile_y1, OPJ_UINT32 * p_nb_comps, - opj_bool * p_go_on, + OPJ_BOOL * p_go_on, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -2151,7 +2744,7 @@ opj_bool opj_jp2_read_tile_header ( opj_jp2_t * p_jp2, p_manager); } -opj_bool opj_jp2_write_tile ( opj_jp2_t *p_jp2, +OPJ_BOOL opj_jp2_write_tile ( opj_jp2_t *p_jp2, OPJ_UINT32 p_tile_index, OPJ_BYTE * p_data, OPJ_UINT32 p_data_size, @@ -2163,7 +2756,7 @@ opj_bool opj_jp2_write_tile ( opj_jp2_t *p_jp2, return opj_j2k_write_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,p_stream,p_manager); } -opj_bool opj_jp2_decode_tile ( opj_jp2_t * p_jp2, +OPJ_BOOL opj_jp2_decode_tile ( opj_jp2_t * p_jp2, OPJ_UINT32 p_tile_index, OPJ_BYTE * p_data, OPJ_UINT32 p_data_size, @@ -2242,7 +2835,7 @@ void opj_jp2_destroy(opj_jp2_t *jp2) } } -opj_bool opj_jp2_set_decode_area( opj_jp2_t *p_jp2, +OPJ_BOOL opj_jp2_set_decode_area( opj_jp2_t *p_jp2, opj_image_t* p_image, OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, OPJ_INT32 p_end_x, OPJ_INT32 p_end_y, @@ -2252,7 +2845,7 @@ opj_bool opj_jp2_set_decode_area( opj_jp2_t *p_jp2, return opj_j2k_set_decode_area(p_jp2->j2k, p_image, p_start_x, p_start_y, p_end_x, p_end_y, p_manager); } -opj_bool opj_jp2_get_tile( opj_jp2_t *p_jp2, +OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, opj_stream_private_t *p_stream, opj_image_t* p_image, opj_event_mgr_t * p_manager, @@ -2269,20 +2862,23 @@ 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 = CLRSPC_SRGB; + p_image->color_space = OPJ_CLRSPC_SRGB; else if (p_jp2->enumcs == 17) - p_image->color_space = CLRSPC_GRAY; + p_image->color_space = OPJ_CLRSPC_GRAY; else if (p_jp2->enumcs == 18) - p_image->color_space = CLRSPC_SYCC; + 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 = CLRSPC_UNKNOWN; - - /* Apply the color space if needed */ - if(p_jp2->color.jp2_cdef) { - opj_jp2_apply_cdef(p_image, &(p_jp2->color)); - } + p_image->color_space = OPJ_CLRSPC_UNKNOWN; if(p_jp2->color.jp2_pclr) { /* Part 1, I.5.3.4: Either both or none : */ @@ -2291,6 +2887,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; @@ -2305,11 +2906,10 @@ opj_bool opj_jp2_get_tile( opj_jp2_t *p_jp2, /* JP2 encoder interface */ /* ----------------------------------------------------------------------- */ -opj_jp2_t* opj_jp2_create(opj_bool p_is_decoder) +opj_jp2_t* opj_jp2_create(OPJ_BOOL p_is_decoder) { - opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); + opj_jp2_t *jp2 = (opj_jp2_t*)opj_calloc(1,sizeof(opj_jp2_t)); if (jp2) { - memset(jp2,0,sizeof(opj_jp2_t)); /* create the J2K codec */ if (! p_is_decoder) { @@ -2369,7 +2969,7 @@ opj_codestream_info_v2_t* jp2_get_cstr_info(opj_jp2_t* p_jp2) return j2k_get_cstr_info(p_jp2->j2k); } -opj_bool opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2, +OPJ_BOOL opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager) { @@ -2379,7 +2979,7 @@ opj_bool opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2, /* JPIP specific */ #ifdef USE_JPIP -static opj_bool opj_jpip_write_iptr(opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_write_iptr(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -2421,7 +3021,7 @@ static opj_bool opj_jpip_write_iptr(opj_jp2_t *jp2, return OPJ_TRUE; } -static opj_bool opj_jpip_write_fidx(opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_write_fidx(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -2453,7 +3053,7 @@ static opj_bool opj_jpip_write_fidx(opj_jp2_t *jp2, return OPJ_TRUE; } -static opj_bool opj_jpip_write_cidx(opj_jp2_t *jp2, +static OPJ_BOOL opj_jpip_write_cidx(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -2496,6 +3096,7 @@ static opj_bool opj_jpip_write_cidx(opj_jp2_t *jp2, return OPJ_TRUE; } +#if 0 static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int length_idx, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -2528,8 +3129,10 @@ static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int le opj_stream_write_data(cio,l_data_header,4,p_manager); opj_stream_seek(cio, lenp+len,p_manager); } +#endif +#if 0 static int write_fidx( int offset_jp2c, int length_jp2c, int offset_idx, int length_idx, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -2551,4 +3154,5 @@ static int write_fidx( int offset_jp2c, int length_jp2c, int offset_idx, int len return len; } +#endif #endif /* USE_JPIP */