static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image);
+static void opj_get_tile_dimensions(opj_image_t * l_image,
+ opj_tcd_tilecomp_t * l_tilec,
+ opj_image_comp_t * l_img_comp,
+ OPJ_UINT32* l_size_comp,
+ OPJ_UINT32* l_width,
+ OPJ_UINT32* l_height,
+ OPJ_UINT32* l_offset_x,
+ OPJ_UINT32* l_offset_y,
+ OPJ_UINT32* l_image_width,
+ OPJ_UINT32* l_stride,
+ OPJ_UINT32* l_tile_offset);
+
static void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data);
static OPJ_BOOL opj_j2k_post_write_tile (opj_j2k_t * p_j2k,
- OPJ_BYTE * p_data,
- OPJ_UINT32 p_data_size,
opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager );
OPJ_UINT32 l_nb_comp_remain;
OPJ_UINT32 l_remaining_size;
OPJ_UINT32 l_nb_tiles;
- OPJ_UINT32 l_tmp;
+ OPJ_UINT32 l_tmp, l_tx1, l_ty1;
opj_image_t *l_image = 00;
opj_cp_t *l_cp = 00;
opj_image_comp_t * l_img_comp = 00;
}
/* testcase 4035.pdf.SIGSEGV.d8b.3375 */
- if (l_image->x0 > l_image->x1 || l_image->y0 > l_image->y1) {
- opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0);
+ /* testcase issue427-null-image-size.jp2 */
+ if ((l_image->x0 >= l_image->x1) || (l_image->y0 >= l_image->y1)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative or zero image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0);
return OPJ_FALSE;
}
/* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */
return OPJ_FALSE;
}
+ /* testcase issue427-illegal-tile-offset.jp2 */
+ l_tx1 = l_cp->tx0 + l_cp->tdx;
+ if (l_tx1 < l_cp->tx0) { /* manage overflow */
+ l_tx1 = 0xFFFFFFFFU;
+ }
+ l_ty1 = l_cp->ty0 + l_cp->tdy;
+ if (l_ty1 < l_cp->ty0) { /* manage overflow */
+ l_ty1 = 0xFFFFFFFFU;
+ }
+ if ((l_cp->tx0 > l_image->x0) || (l_cp->ty0 > l_image->y0) || (l_tx1 <= l_image->x0) || (l_ty1 <= l_image->y0) ) {
+ opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: illegal tile offset\n");
+ return OPJ_FALSE;
+ }
+
#ifdef USE_JPWL
if (l_cp->correct) {
/* if JPWL is on, we check whether TX errors have damaged
/* First PPM marker */
if (l_Z_ppm == 0) {
+ if (l_cp->ppm_data != NULL) {
+ opj_event_msg(p_manager, EVT_ERROR, "Zppm O already processed. Found twice.\n");
+ opj_free(l_cp->ppm_data);
+ l_cp->ppm_data = NULL;
+ l_cp->ppm_buffer = NULL;
+ l_cp->ppm = 0; /* do not use PPM */
+ return OPJ_FALSE;
+ }
/* We need now at least the Nppm^0 element */
if (p_header_size < 4) {
opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
OPJ_BYTE *new_ppm_data;
/* Increase the size of ppm_data to add the new Ippm series*/
assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating");
+ /* Overflow check */
+ if ((l_cp->ppm_len + l_N_ppm) < l_N_ppm) {
+ opj_free(l_cp->ppm_data);
+ l_cp->ppm_data = NULL;
+ l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */
+ l_cp->ppm_len = 0;
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new (complete) Ippm series\n");
+ return OPJ_FALSE;
+ }
new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm);
if (! new_ppm_data) {
opj_free(l_cp->ppm_data);
if (l_remaining_data) {
OPJ_BYTE *new_ppm_data;
assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating");
+
+ /* Overflow check */
+ if ((l_cp->ppm_len + l_N_ppm) < l_N_ppm) {
+ opj_free(l_cp->ppm_data);
+ l_cp->ppm_data = NULL;
+ l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */
+ l_cp->ppm_len = 0;
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new (complete) Ippm series\n");
+ return OPJ_FALSE;
+ }
new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm);
if (! new_ppm_data) {
opj_free(l_cp->ppm_data);
return OPJ_FALSE;
}
+ if ((parameters->numresolution <= 0) || (parameters->numresolution > OPJ_J2K_MAXRLVLS)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid number of resolutions : %d not in range [1,%d]\n", parameters->numresolution, OPJ_J2K_MAXRLVLS);
+ return OPJ_FALSE;
+ }
+
/* keep a link to cp so that we can destroy it later in j2k_destroy_compress */
cp = &(p_j2k->m_cp);
}
}
else {
- if(tcp->mct==1 && image->numcomps == 3) { /* RGB->YCC MCT is enabled */
+ if(tcp->mct==1 && image->numcomps >= 3) { /* RGB->YCC MCT is enabled */
if ((image->comps[0].dx != image->comps[1].dx) ||
(image->comps[0].dx != image->comps[2].dx) ||
(image->comps[0].dy != image->comps[1].dy) ||
/* make sure a validation list is present */
l_is_valid &= (p_j2k->m_validation_list != 00);
- if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) {
+ /* ISO 15444-1:2004 states between 1 & 33 (0 -> 32) */
+ /* 33 (32) would always fail the check below (if a cast to 64bits was done) */
+ /* FIXME Shall we change OPJ_J2K_MAXRLVLS to 32 ? */
+ if ((p_j2k->m_cp.tcps->tccps->numresolutions <= 0) || (p_j2k->m_cp.tcps->tccps->numresolutions > 32)) {
opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n");
return OPJ_FALSE;
}
- if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) {
+ if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << (p_j2k->m_cp.tcps->tccps->numresolutions - 1U))) {
+ opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n");
+ return OPJ_FALSE;
+ }
+
+ if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << (p_j2k->m_cp.tcps->tccps->numresolutions - 1U))) {
opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n");
return OPJ_FALSE;
}
OPJ_UINT32 l_current_marker;
OPJ_UINT32 l_marker_size;
const opj_dec_memory_marker_handler_t * l_marker_handler = 00;
+ OPJ_BOOL l_has_siz = 0;
+ OPJ_BOOL l_has_cod = 0;
+ OPJ_BOOL l_has_qcd = 0;
/* preconditions */
assert(p_stream != 00);
l_marker_handler = opj_j2k_get_marker_handler(l_current_marker);
}
+ if (l_marker_handler->id == J2K_MS_SIZ) {
+ /* Mark required SIZ marker as found */
+ l_has_siz = 1;
+ }
+ if (l_marker_handler->id == J2K_MS_COD) {
+ /* Mark required COD marker as found */
+ l_has_cod = 1;
+ }
+ if (l_marker_handler->id == J2K_MS_QCD) {
+ /* Mark required QCD marker as found */
+ l_has_qcd = 1;
+ }
+
/* Check if the marker is known and if it is the right place to find it */
if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) {
opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n");
opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2);
}
+ if (l_has_siz == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "required SIZ marker not found in main header\n");
+ return OPJ_FALSE;
+ }
+ if (l_has_cod == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "required COD marker not found in main header\n");
+ return OPJ_FALSE;
+ }
+ if (l_has_qcd == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "required QCD marker not found in main header\n");
+ return OPJ_FALSE;
+ }
+
opj_event_msg(p_manager, EVT_INFO, "Main header has been correctly decoded.\n");
/* Position of the last element if the main header */
for (i = 0; i < l_tccp->numresolutions; ++i) {
opj_read_bytes(l_current_ptr,&l_tmp ,1); /* SPcoc (I_i) */
++l_current_ptr;
+ /* Precinct exponent 0 is only allowed for lowest resolution level (Table A.21) */
+ if ((i != 0) && (((l_tmp & 0xf) == 0) || ((l_tmp >> 4) == 0))) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid precinct size\n");
+ return OPJ_FALSE;
+ }
l_tccp->prcw[i] = l_tmp & 0xf;
l_tccp->prch[i] = l_tmp >> 4;
}
opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager )
{
- OPJ_UINT32 i;
+ OPJ_UINT32 i, j;
OPJ_UINT32 l_nb_tiles;
- OPJ_UINT32 l_max_tile_size, l_current_tile_size;
- OPJ_BYTE * l_current_data;
+ OPJ_UINT32 l_max_tile_size = 0, l_current_tile_size;
+ OPJ_BYTE * l_current_data = 00;
+ opj_tcd_t* p_tcd = 00;
/* preconditions */
assert(p_j2k != 00);
assert(p_stream != 00);
assert(p_manager != 00);
-
- l_current_data = (OPJ_BYTE*)opj_malloc(1000);
- if (! l_current_data) {
- opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n");
- return OPJ_FALSE;
- }
- l_max_tile_size = 1000;
+
+ p_tcd = p_j2k->m_tcd;
l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
for (i=0;i<l_nb_tiles;++i) {
if (! opj_j2k_pre_write_tile(p_j2k,i,p_stream,p_manager)) {
- opj_free(l_current_data);
+ if (l_current_data) {
+ opj_free(l_current_data);
+ }
return OPJ_FALSE;
}
- l_current_tile_size = opj_tcd_get_encoded_tile_size(p_j2k->m_tcd);
- if (l_current_tile_size > l_max_tile_size) {
- OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size);
- if (! l_new_current_data) {
- opj_free(l_current_data);
- opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n");
- return OPJ_FALSE;
+ /* if we only have one tile, then simply set tile component data equal to image component data */
+ /* otherwise, allocate the data */
+ for (j=0;j<p_j2k->m_tcd->image->numcomps;++j) {
+ opj_tcd_tilecomp_t* l_tilec = p_tcd->tcd_image->tiles->comps + j;
+ if (l_nb_tiles == 1) {
+ opj_image_comp_t * l_img_comp = p_tcd->image->comps + j;
+ l_tilec->data = l_img_comp->data;
+ l_tilec->ownsData = OPJ_FALSE;
+ } else {
+ if(! opj_alloc_tile_component_data(l_tilec)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Error allocating tile component data." );
+ if (l_current_data) {
+ opj_free(l_current_data);
+ }
+ return OPJ_FALSE;
+ }
+ opj_alloc_tile_component_data(l_tilec);
}
- l_current_data = l_new_current_data;
- l_max_tile_size = l_current_tile_size;
}
+ l_current_tile_size = opj_tcd_get_encoded_tile_size(p_j2k->m_tcd);
+ if (l_nb_tiles > 1) {
+ if (l_current_tile_size > l_max_tile_size) {
+ OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size);
+ if (! l_new_current_data) {
+ if (l_current_data) {
+ opj_free(l_current_data);
+ }
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n");
+ return OPJ_FALSE;
+ }
+ l_current_data = l_new_current_data;
+ l_max_tile_size = l_current_tile_size;
+ }
- opj_j2k_get_tile_data(p_j2k->m_tcd,l_current_data);
+ /* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */
+ /* 32 bit components @ 8 bit precision get converted to 8 bit */
+ /* 32 bit components @ 16 bit precision get converted to 16 bit */
+ opj_j2k_get_tile_data(p_j2k->m_tcd,l_current_data);
- if (! opj_j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) {
+ /* now copy this data into the tile component */
+ if (! opj_tcd_copy_tile_data(p_j2k->m_tcd,l_current_data,l_current_tile_size)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." );
+ return OPJ_FALSE;
+ }
+ }
+
+ if (! opj_j2k_post_write_tile (p_j2k,p_stream,p_manager)) {
return OPJ_FALSE;
}
}
- opj_free(l_current_data);
+ if (l_current_data) {
+ opj_free(l_current_data);
+ }
return OPJ_TRUE;
}
return OPJ_TRUE;
}
+void opj_get_tile_dimensions(opj_image_t * l_image,
+ opj_tcd_tilecomp_t * l_tilec,
+ opj_image_comp_t * l_img_comp,
+ OPJ_UINT32* l_size_comp,
+ OPJ_UINT32* l_width,
+ OPJ_UINT32* l_height,
+ OPJ_UINT32* l_offset_x,
+ OPJ_UINT32* l_offset_y,
+ OPJ_UINT32* l_image_width,
+ OPJ_UINT32* l_stride,
+ OPJ_UINT32* l_tile_offset) {
+ OPJ_UINT32 l_remaining;
+ *l_size_comp = l_img_comp->prec >> 3; /* (/8) */
+ l_remaining = l_img_comp->prec & 7; /* (%8) */
+ if (l_remaining) {
+ *l_size_comp += 1;
+ }
+
+ if (*l_size_comp == 3) {
+ *l_size_comp = 4;
+ }
+
+ *l_width = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
+ *l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
+ *l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
+ *l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy);
+ *l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
+ *l_stride = *l_image_width - *l_width;
+ *l_tile_offset = ((OPJ_UINT32)l_tilec->x0 - *l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - *l_offset_y) * *l_image_width;
+}
+
void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data)
{
OPJ_UINT32 i,j,k = 0;
- OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width;
- opj_image_comp_t * l_img_comp = 00;
- opj_tcd_tilecomp_t * l_tilec = 00;
- opj_image_t * l_image = 00;
- OPJ_UINT32 l_size_comp, l_remaining;
- OPJ_INT32 * l_src_ptr;
- l_tilec = p_tcd->tcd_image->tiles->comps;
- l_image = p_tcd->image;
- l_img_comp = l_image->comps;
for (i=0;i<p_tcd->image->numcomps;++i) {
- l_size_comp = l_img_comp->prec >> 3; /* (/8) */
- l_remaining = l_img_comp->prec & 7; /* (%8) */
- if (l_remaining) {
- ++l_size_comp;
- }
-
- if (l_size_comp == 3) {
- l_size_comp = 4;
- }
-
- l_width = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
- l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
- l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
- l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy);
- l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx);
- l_stride = l_image_width - l_width;
- l_src_ptr = l_img_comp->data + ((OPJ_UINT32)l_tilec->x0 - l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - l_offset_y) * l_image_width;
+ opj_image_t * l_image = p_tcd->image;
+ OPJ_INT32 * l_src_ptr;
+ opj_tcd_tilecomp_t * l_tilec = p_tcd->tcd_image->tiles->comps + i;
+ opj_image_comp_t * l_img_comp = l_image->comps + i;
+ OPJ_UINT32 l_size_comp,l_width,l_height,l_offset_x,l_offset_y, l_image_width,l_stride,l_tile_offset;
+
+ opj_get_tile_dimensions(l_image,
+ l_tilec,
+ l_img_comp,
+ &l_size_comp,
+ &l_width,
+ &l_height,
+ &l_offset_x,
+ &l_offset_y,
+ &l_image_width,
+ &l_stride,
+ &l_tile_offset);
+
+ l_src_ptr = l_img_comp->data + l_tile_offset;
switch (l_size_comp) {
case 1:
}
break;
}
-
- ++l_img_comp;
- ++l_tilec;
}
}
OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k,
- OPJ_BYTE * p_data,
- OPJ_UINT32 p_data_size,
opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager )
{
- opj_tcd_t * l_tcd = 00;
OPJ_UINT32 l_nb_bytes_written;
OPJ_BYTE * l_current_data = 00;
OPJ_UINT32 l_tile_size = 0;
/* preconditions */
assert(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data);
- l_tcd = p_j2k->m_tcd;
-
l_tile_size = p_j2k->m_specific_param.m_encoder.m_encoded_tile_size;
l_available_data = l_tile_size;
l_current_data = p_j2k->m_specific_param.m_encoder.m_encoded_tile_data;
- if (! opj_tcd_copy_tile_data(l_tcd,p_data,p_data_size)) {
- opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." );
- return OPJ_FALSE;
- }
-
l_nb_bytes_written = 0;
if (! opj_j2k_write_first_tile_part(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) {
return OPJ_FALSE;
return OPJ_FALSE;
}
else {
- if (! opj_j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager)) {
+ OPJ_UINT32 j;
+ /* Allocate data */
+ for (j=0;j<p_j2k->m_tcd->image->numcomps;++j) {
+ opj_tcd_tilecomp_t* l_tilec = p_j2k->m_tcd->tcd_image->tiles->comps + j;
+
+ if(! opj_alloc_tile_component_data(l_tilec)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Error allocating tile component data." );
+ return OPJ_FALSE;
+ }
+ }
+
+ /* now copy data into the the tile component */
+ if (! opj_tcd_copy_tile_data(p_j2k->m_tcd,p_data,p_data_size)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." );
+ return OPJ_FALSE;
+ }
+ if (! opj_j2k_post_write_tile(p_j2k,p_stream,p_manager)) {
opj_event_msg(p_manager, EVT_ERROR, "Error while opj_j2k_post_write_tile with tile index = %d\n", p_tile_index);
return OPJ_FALSE;
}