Merge pull request #514 from mayeut/issue-254

Correctly decode files with incorrect tile-part header fields (TPsot==TNsot)
Fixes uclouvain/openjpeg#254
This commit is contained in:
mayeut 2015-07-04 00:47:59 +02:00
commit 237ddd72f1
4 changed files with 218 additions and 36 deletions

View File

@ -41,6 +41,11 @@ if(BUILD_JPIP)
)
endif()
option(OPJ_DISABLE_TPSOT_FIX "Disable TPsot==TNsot fix. See https://github.com/uclouvain/openjpeg/issues/254." OFF)
if(OPJ_DISABLE_TPSOT_FIX)
add_definitions(-DOPJ_DISABLE_TPSOT_FIX)
endif()
# Build the library
if(WIN32)
if(BUILD_SHARED_LIBS)

View File

@ -780,12 +780,32 @@ static OPJ_BOOL opj_j2k_write_sot( opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager );
/**
* Reads a PPT marker (Packed packet headers, tile-part header)
* Reads values from a SOT marker (Start of tile-part)
*
* @param p_header_data the data contained in the PPT box.
* @param p_j2k the jpeg2000 codec.
* the j2k decoder state is not affected. No side effects, no checks except for p_header_size.
*
* @param p_header_data the data contained in the SOT marker.
* @param p_header_size the size of the data contained in the SOT marker.
* @param p_tile_no Isot.
* @param p_tot_len Psot.
* @param p_current_part TPsot.
* @param p_num_parts TNsot.
* @param p_manager the user event manager.
*/
static OPJ_BOOL opj_j2k_get_sot_values(OPJ_BYTE * p_header_data,
OPJ_UINT32 p_header_size,
OPJ_UINT32* p_tile_no,
OPJ_UINT32* p_tot_len,
OPJ_UINT32* p_current_part,
OPJ_UINT32* p_num_parts,
opj_event_mgr_t * p_manager );
/**
* Reads a SOT marker (Start of tile-part)
*
* @param p_header_data the data contained in the SOT marker.
* @param p_j2k the jpeg2000 codec.
* @param p_header_size the size of the data contained in the PPT marker.
* @param p_manager the user event manager.
* @param p_manager the user event manager.
*/
static OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
OPJ_BYTE * p_header_data,
@ -1179,6 +1199,18 @@ static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_ima
static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager);
/**
* Checks for invalid number of tile-parts in SOT marker (TPsot==TNsot). See issue 254.
*
* @param p_stream the stream to read data from.
* @param tile_no tile number we're looking for.
* @param p_correction_needed output value. if true, non conformant codestream needs TNsot correction.
* @param p_manager the user event manager.
*
* @return true if the function was successful, false else.
*/
static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t *p_stream, OPJ_UINT32 tile_no, OPJ_BOOL* p_correction_needed, opj_event_mgr_t * p_manager );
/*@}*/
/*@}*/
@ -4018,6 +4050,35 @@ OPJ_BOOL opj_j2k_write_sot( opj_j2k_t *p_j2k,
return OPJ_TRUE;
}
static OPJ_BOOL opj_j2k_get_sot_values(OPJ_BYTE * p_header_data,
OPJ_UINT32 p_header_size,
OPJ_UINT32* p_tile_no,
OPJ_UINT32* p_tot_len,
OPJ_UINT32* p_current_part,
OPJ_UINT32* p_num_parts,
opj_event_mgr_t * p_manager )
{
/* preconditions */
assert(p_header_data != 00);
assert(p_manager != 00);
/* Size of this marker is fixed = 12 (we have already read marker and its size)*/
if (p_header_size != 8) {
opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n");
return OPJ_FALSE;
}
opj_read_bytes(p_header_data,p_tile_no,2); /* Isot */
p_header_data+=2;
opj_read_bytes(p_header_data,p_tot_len,4); /* Psot */
p_header_data+=4;
opj_read_bytes(p_header_data,p_current_part,1); /* TPsot */
++p_header_data;
opj_read_bytes(p_header_data,p_num_parts ,1); /* TNsot */
++p_header_data;
return OPJ_TRUE;
}
OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
OPJ_BYTE * p_header_data,
OPJ_UINT32 p_header_size,
@ -4030,19 +4091,16 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
OPJ_UINT32 l_tile_x,l_tile_y;
/* preconditions */
assert(p_header_data != 00);
assert(p_j2k != 00);
assert(p_manager != 00);
/* Size of this marker is fixed = 12 (we have already read marker and its size)*/
if (p_header_size != 8) {
if (! opj_j2k_get_sot_values(p_header_data, p_header_size, &(p_j2k->m_current_tile_number), &l_tot_len, &l_current_part, &l_num_parts, p_manager)) {
opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n");
return OPJ_FALSE;
}
l_cp = &(p_j2k->m_cp);
opj_read_bytes(p_header_data,&(p_j2k->m_current_tile_number),2); /* Isot */
p_header_data+=2;
/* testcase 2.pdf.SIGFPE.706.1112 */
if (p_j2k->m_current_tile_number >= l_cp->tw * l_cp->th) {
@ -4085,9 +4143,6 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
/* Optimization possible here with a more complex data structure and with the removing of tiles */
/* since the time taken by this function can only grow at the time */
opj_read_bytes(p_header_data,&l_tot_len,4); /* Psot */
p_header_data+=4;
/* PSot should be equal to zero or >=14 or <= 2^32-1 */
if ((l_tot_len !=0 ) && (l_tot_len < 14) )
{
@ -4130,13 +4185,8 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
}
opj_read_bytes(p_header_data,&l_current_part ,1); /* TPsot */
++p_header_data;
opj_read_bytes(p_header_data,&l_num_parts ,1); /* TNsot */
++p_header_data;
if (l_num_parts != 0) { /* Number of tile-part header is provided by this tile-part header */
l_num_parts += p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction;
/* Useful to manage the case of textGBR.jp2 file because two values of TNSot are allowed: the correct numbers of
* tile-parts for that tile and zero (A.4.2 of 15444-1 : 2002). */
if (l_tcp->m_nb_tile_parts) {
@ -7680,6 +7730,104 @@ void opj_j2k_cp_destroy (opj_cp_t *p_cp)
}
}
static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t *p_stream, OPJ_UINT32 tile_no, OPJ_BOOL* p_correction_needed, opj_event_mgr_t * p_manager )
{
OPJ_BYTE l_header_data[10];
OPJ_OFF_T l_stream_pos_backup;
OPJ_UINT32 l_current_marker;
OPJ_UINT32 l_marker_size;
OPJ_UINT32 l_tile_no, l_tot_len, l_current_part, l_num_parts;
/* initialize to no correction needed */
*p_correction_needed = OPJ_FALSE;
l_stream_pos_backup = opj_stream_tell(p_stream);
if (l_stream_pos_backup == -1) {
/* let's do nothing */
return OPJ_TRUE;
}
for (;;) {
/* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */
if (opj_stream_read_data(p_stream,l_header_data, 2, p_manager) != 2) {
/* assume all is OK */
if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
return OPJ_FALSE;
}
return OPJ_TRUE;
}
/* Read 2 bytes from buffer as the new marker ID */
opj_read_bytes(l_header_data, &l_current_marker, 2);
if (l_current_marker != J2K_MS_SOT) {
/* assume all is OK */
if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
return OPJ_FALSE;
}
return OPJ_TRUE;
}
/* Try to read 2 bytes (the marker size) from stream and copy them into the buffer */
if (opj_stream_read_data(p_stream, l_header_data, 2, p_manager) != 2) {
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
return OPJ_FALSE;
}
/* Read 2 bytes from the buffer as the marker size */
opj_read_bytes(l_header_data, &l_marker_size, 2);
/* Check marker size for SOT Marker */
if (l_marker_size != 10) {
opj_event_msg(p_manager, EVT_ERROR, "Inconsistent marker size\n");
return OPJ_FALSE;
}
l_marker_size -= 2;
if (opj_stream_read_data(p_stream, l_header_data, l_marker_size, p_manager) != l_marker_size) {
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
return OPJ_FALSE;
}
if (! opj_j2k_get_sot_values(l_header_data, l_marker_size, &l_tile_no, &l_tot_len, &l_current_part, &l_num_parts, p_manager)) {
return OPJ_FALSE;
}
if (l_tile_no == tile_no) {
/* we found what we were looking for */
break;
}
if ((l_tot_len == 0U) || (l_tot_len < 14U)) {
/* last SOT until EOC or invalid Psot value */
/* assume all is OK */
if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
return OPJ_FALSE;
}
return OPJ_TRUE;
}
l_tot_len -= 12U;
/* look for next SOT marker */
if (opj_stream_skip(p_stream, (OPJ_OFF_T)(l_tot_len), p_manager) != (OPJ_OFF_T)(l_tot_len)) {
/* assume all is OK */
if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
return OPJ_FALSE;
}
return OPJ_TRUE;
}
}
/* check for correction */
if (l_current_part == l_num_parts) {
*p_correction_needed = OPJ_TRUE;
}
if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
return OPJ_FALSE;
}
return OPJ_TRUE;
}
OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k,
OPJ_UINT32 * p_tile_index,
OPJ_UINT32 * p_data_size,
@ -7844,7 +7992,30 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k,
if (! opj_j2k_read_sod(p_j2k, p_stream, p_manager)) {
return OPJ_FALSE;
}
if (p_j2k->m_specific_param.m_decoder.m_can_decode && !p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked) {
/* Issue 254 */
OPJ_BOOL l_correction_needed;
p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1;
if(!opj_j2k_need_nb_tile_parts_correction(p_stream, p_j2k->m_current_tile_number, &l_correction_needed, p_manager)) {
opj_event_msg(p_manager, EVT_ERROR, "opj_j2k_apply_nb_tile_parts_correction error\n");
return OPJ_FALSE;
}
if (l_correction_needed) {
OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th;
OPJ_UINT32 l_tile_no;
p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction = 1;
/* correct tiles */
for (l_tile_no = 0U; l_tile_no < l_nb_tiles; ++l_tile_no) {
if (p_j2k->m_cp.tcps[l_tile_no].m_nb_tile_parts != 0U) {
p_j2k->m_cp.tcps[l_tile_no].m_nb_tile_parts+=1;
}
}
opj_event_msg(p_manager, EVT_WARNING, "Non conformant codestream TPsot==TNsot.\n");
}
}
if (! p_j2k->m_specific_param.m_decoder.m_can_decode){
/* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */
if (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) {
@ -8431,6 +8602,10 @@ opj_j2k_t* opj_j2k_create_decompress(void)
l_j2k->m_is_decoder = 1;
l_j2k->m_cp.m_is_decoder = 1;
#ifdef OPJ_DISABLE_TPSOT_FIX
l_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1;
#endif
l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_calloc(1,sizeof(opj_tcp_t));
if (!l_j2k->m_specific_param.m_decoder.m_default_tcp) {
opj_j2k_destroy(l_j2k);

View File

@ -483,6 +483,9 @@ typedef struct opj_j2k_dec
OPJ_UINT32 m_can_decode : 1;
OPJ_UINT32 m_discard_tiles : 1;
OPJ_UINT32 m_skip_data : 1;
/** TNsot correction : see issue 254 **/
OPJ_UINT32 m_nb_tile_parts_correction_checked : 1;
OPJ_UINT32 m_nb_tile_parts_correction : 1;
} opj_j2k_dec_t;
@ -569,7 +572,6 @@ typedef struct opj_j2k
/** the current tile coder/decoder **/
struct opj_tcd * m_tcd;
}
opj_j2k_t;

View File

@ -37,19 +37,19 @@ cb89739232898a823355861d834b5734 issue205.jp2_0.pgx
a09d34928fd86e6f2d7e6edc1764d2b7 issue205.jp2_1.pgx
6f712d0685f2c5522f01b238365f4284 issue205.jp2_2.pgx
de992d54d59032eb07d21983dbe8155b issue205.jp2_3.pgx
8fae7a39e459409f64e4529d2214087a issue206_image-000.jp2_0.pgx
555a504a93c9a14f61c894da3b393e87 issue206_image-000.jp2_1.pgx
5f06b7c45446ae20c22cada46478a9dc issue206_image-000.jp2_2.pgx
8c0025fe9ffbff839e7735c18f56f596 issue208.jp2_0.pgx
285fedd7e5e92624177d00eaa543e551 issue208.jp2_1.pgx
bc5178a807be5901938d7f555275933f issue208.jp2_2.pgx
37546d44ecf7f2ea40a4f25d177910f3 issue208.jp2_3.pgx
1a507a95237768e41cd0987ad0f134f4 issue206_image-000.jp2_0.pgx
dacea42ff8bb859504820100637de2b6 issue206_image-000.jp2_1.pgx
1831abb207d2c85e9b8d4da308144213 issue206_image-000.jp2_2.pgx
b7073a2c1b5a42f9555eb0f0bd3c6510 issue208.jp2_0.pgx
df65beeb8fd056c8f7b8dfc699caa12b issue208.jp2_1.pgx
15cba2ad37c1a8e1eb3eb4bc42d5a2a2 issue208.jp2_2.pgx
301fabf4aac5729b44aab845580d5038 issue208.jp2_3.pgx
a0823d21d9de699353a3bd1adb23bd1c issue211.jp2_0.pgx
1820161df26c360a62d11800d6cf173f issue211.jp2_1.pgx
e1807db57b5f5192c4b77b83e8b5c477 issue228.j2k_0.pgx
cccccccccccccccccccccccccccccccc issue254.jp2_0.pgx
cccccccccccccccccccccccccccccccc issue254.jp2_1.pgx
cccccccccccccccccccccccccccccccc issue254.jp2_2.pgx
e58242abc2c6d44df187397c55e6fbff issue254.jp2_0.pgx
e58242abc2c6d44df187397c55e6fbff issue254.jp2_1.pgx
e58242abc2c6d44df187397c55e6fbff issue254.jp2_2.pgx
4093cc34d838780b35a8be410247fa7f j2k32.j2k_0.pgx
ce4e556aaa0844b92a92c35c200fc43e j2k32.j2k_1.pgx
ea926520f990640862f3fe6616097613 j2k32.j2k_2.pgx
@ -63,9 +63,9 @@ ea926520f990640862f3fe6616097613 j2k32.j2k_2.pgx
05c062aca83d13b8095460f38a690a08 MarkerIsNotCompliant.j2k_0.pgx
ff73d2bd32951d9e55b02186aac24aff Marrin.jp2_0.pgx
55ce884dd2346af6a5172a434ee578fa Marrin.jp2_1.pgx
41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_0.pgx
41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_1.pgx
41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_2.pgx
9271a64c96094765a8168f9610aabc8b mem-b2b86b74-2753.jp2_0.pgx
9271a64c96094765a8168f9610aabc8b mem-b2b86b74-2753.jp2_1.pgx
9271a64c96094765a8168f9610aabc8b mem-b2b86b74-2753.jp2_2.pgx
97557ab9e38a7aff621e583fbb66b099 merged.jp2_0.pgx
386fbdcd294429733e3272d62ed5a15a merged.jp2_1.pgx
d3907bbd67be1dae31b4377fa4dc0373 merged.jp2_2.pgx
@ -151,9 +151,9 @@ d41856648d936229f1e3e2cf7d7c7a4d p1_06_9_2.j2k.png
518a8f28dacc034982507f43763b88dd relax.jp2_1.pgx
c678b04f4d3e59b9d66a8bce37c553c0 relax.jp2_2.pgx
cdb1d69eb48ffd8545751326b86d9d7e test_lossless.j2k_0.pgx
a37e7e5811d7c0c7adb61582790ccd33 text_GBR.jp2_0.pgx
fc2173be54954a146b4e2887ee14be06 text_GBR.jp2_1.pgx
14108b4fb8d9126750db0424417ed17d text_GBR.jp2_2.pgx
efc9c7f21a542a7888a9eeb73b0f7092 text_GBR.jp2_0.pgx
54790b332b3dcbda28e1bcb31270b946 text_GBR.jp2_1.pgx
d9bcbdc818febb8c0a6bc5f940a4ea85 text_GBR.jp2_2.pgx
a73bec4d6d82c8a64203e8fdf893b86d issue412.jp2_0.pgx
a73bec4d6d82c8a64203e8fdf893b86d issue428.jp2_0.pgx
2354cf24a1cc5e4a3b72896b333ba361 issue412.jp2_1.pgx