Merge pull request #559 from szukw000/cmyk-cielab-esycc
[openjpeg.git] / src / lib / openjp2 / j2k.c
index a9b42697b1c671feef4fd9461bc9c467353043a5..19a48f5648057fc9ed9955ba990450d82dd73d2c 100644 (file)
@@ -1,9 +1,15 @@
 /*
- * 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) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr>
  * Copyright (c) 2006-2007, Parvatha Elangovan
 
 #include "opj_includes.h"
 
-#define CINEMA_24_CS 1302083   /*Codestream length for 24fps*/
-#define CINEMA_48_CS 651041            /*Codestream length for 48fps*/
-#define COMP_24_CS 1041666             /*Maximum size per color component for 2K & 4K @ 24fps*/
-#define COMP_48_CS 520833              /*Maximum size per color component for 2K @ 48fps*/
-
 /** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */
 /*@{*/
 
@@ -50,7 +51,7 @@
 /**
  * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures.
  */
-static void opj_j2k_setup_header_reading (opj_j2k_t *p_j2k);
+static OPJ_BOOL opj_j2k_setup_header_reading (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager);
 
 /**
  * The read header procedure.
@@ -89,19 +90,19 @@ static OPJ_BOOL opj_j2k_decoding_validation (   opj_j2k_t * p_j2k,
  * 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_j2k_setup_encoding_validation (opj_j2k_t *p_j2k);
+static OPJ_BOOL opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager);
 
 /**
  * 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_j2k_setup_decoding_validation (opj_j2k_t *p_j2k);
+static OPJ_BOOL opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager);
 
 /**
  * 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_j2k_setup_end_compress (opj_j2k_t *p_j2k);
+static OPJ_BOOL opj_j2k_setup_end_compress (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager);
 
 /**
  * The mct encoding validation procedure.
@@ -337,11 +338,21 @@ static OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k,
 
 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 );
 
@@ -349,7 +360,7 @@ static OPJ_BOOL opj_j2k_post_write_tile (opj_j2k_t * p_j2k,
  * Sets up the procedures to do on writing header.
  * Developers wanting to extend the library can add their own writing procedures.
  */
-static void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k);
+static OPJ_BOOL opj_j2k_setup_header_writing (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager);
 
 static OPJ_BOOL opj_j2k_write_first_tile_part(  opj_j2k_t *p_j2k,
                                                                                             OPJ_BYTE * p_data,
@@ -707,28 +718,28 @@ static OPJ_BOOL opj_j2k_read_plt (  opj_j2k_t *p_j2k,
                                     OPJ_UINT32 p_header_size,
                                     opj_event_mgr_t * p_manager );
 
-#if 0
 /**
- * Reads a PPM marker (Packed packet headers, main header)
+ * Reads a PPM marker (Packed headers, main header)
  *
  * @param       p_header_data   the data contained in the POC box.
  * @param       p_j2k                   the jpeg2000 codec.
  * @param       p_header_size   the size of the data contained in the POC marker.
  * @param       p_manager               the user event manager.
-*/
-static OPJ_BOOL j2k_read_ppm_v2 (
-                                                opj_j2k_t *p_j2k,
-                                                OPJ_BYTE * p_header_data,
-                                                OPJ_UINT32 p_header_size,
-                                                struct opj_event_mgr * p_manager
-                                        );
-#endif
+ */
 
-static OPJ_BOOL j2k_read_ppm_v3 (
-                                                opj_j2k_t *p_j2k,
-                                                OPJ_BYTE * p_header_data,
-                                                OPJ_UINT32 p_header_size,
-                                                opj_event_mgr_t * p_manager );
+static OPJ_BOOL opj_j2k_read_ppm (
+                                                                                                                                                opj_j2k_t *p_j2k,
+                                                                                                                                                OPJ_BYTE * p_header_data,
+                                                                                                                                                OPJ_UINT32 p_header_size,
+                                                                                                                                                opj_event_mgr_t * p_manager );
+
+/**
+ * Merges all PPM markers read (Packed headers, main header)
+ *
+ * @param       p_cp      main coding parameters.
+ * @param       p_manager the user event manager.
+ */
+static OPJ_BOOL opj_j2k_merge_ppm ( opj_cp_t *p_cp, opj_event_mgr_t * p_manager );
 
 /**
  * Reads a PPT marker (Packed packet headers, tile-part header)
@@ -742,6 +753,17 @@ static OPJ_BOOL opj_j2k_read_ppt (  opj_j2k_t *p_j2k,
                                     OPJ_BYTE * p_header_data,
                                     OPJ_UINT32 p_header_size,
                                     opj_event_mgr_t * p_manager );
+
+/**
+ * Merges all PPT markers read (Packed headers, tile-part header)
+ *
+ * @param       p_tcp   the tile.
+ * @param       p_manager               the user event manager.
+ */
+static OPJ_BOOL opj_j2k_merge_ppt (  opj_tcp_t *p_tcp,
+                                                                                                                                          opj_event_mgr_t * p_manager );
+
+
 /**
  * Writes the TLM marker (Tile Length Marker)
  *
@@ -769,12 +791,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,
@@ -810,7 +852,7 @@ static OPJ_BOOL opj_j2k_read_sod(   opj_j2k_t *p_j2k,
                                     opj_stream_private_t *p_stream,
                                     opj_event_mgr_t * p_manager );
 
-void opj_j2k_update_tlm (opj_j2k_t * p_j2k, OPJ_UINT32 p_tile_part_size )
+static void opj_j2k_update_tlm (opj_j2k_t * p_j2k, OPJ_UINT32 p_tile_part_size )
 {
         opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_j2k->m_current_tile_number,1);            /* PSOT */
         ++p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current;
@@ -1166,7 +1208,19 @@ static int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres);
 
 static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager);
 
-static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager);
+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 );
 
 /*@}*/
 
@@ -1178,7 +1232,7 @@ typedef struct j2k_prog_order{
         char str_prog[5];
 }j2k_prog_order_t;
 
-j2k_prog_order_t j2k_prog_order_list[] = {
+static j2k_prog_order_t j2k_prog_order_list[] = {
         {OPJ_CPRL, "CPRL"},
         {OPJ_LRCP, "LRCP"},
         {OPJ_PCRL, "PCRL"},
@@ -1200,7 +1254,7 @@ static const OPJ_UINT32 MCT_ELEMENT_SIZE [] =
 
 typedef void (* opj_j2k_mct_function) (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem);
 
-const opj_j2k_mct_function j2k_mct_read_functions_to_float [] =
+static const opj_j2k_mct_function j2k_mct_read_functions_to_float [] =
 {
         opj_j2k_read_int16_to_float,
         opj_j2k_read_int32_to_float,
@@ -1208,7 +1262,7 @@ const opj_j2k_mct_function j2k_mct_read_functions_to_float [] =
         opj_j2k_read_float64_to_float
 };
 
-const opj_j2k_mct_function j2k_mct_read_functions_to_int32 [] =
+static const opj_j2k_mct_function j2k_mct_read_functions_to_int32 [] =
 {
         opj_j2k_read_int16_to_int32,
         opj_j2k_read_int32_to_int32,
@@ -1216,7 +1270,7 @@ const opj_j2k_mct_function j2k_mct_read_functions_to_int32 [] =
         opj_j2k_read_float64_to_int32
 };
 
-const opj_j2k_mct_function j2k_mct_write_functions_from_float [] =
+static const opj_j2k_mct_function j2k_mct_write_functions_from_float [] =
 {
         opj_j2k_write_float_to_int16,
         opj_j2k_write_float_to_int32,
@@ -1238,7 +1292,7 @@ typedef struct opj_dec_memory_marker_handler
 }
 opj_dec_memory_marker_handler_t;
 
-const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] =
+static const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] =
 {
   {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, opj_j2k_read_sot},
   {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, opj_j2k_read_cod},
@@ -1251,7 +1305,7 @@ const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] =
   {J2K_MS_TLM, J2K_STATE_MH, opj_j2k_read_tlm},
   {J2K_MS_PLM, J2K_STATE_MH, opj_j2k_read_plm},
   {J2K_MS_PLT, J2K_STATE_TPH, opj_j2k_read_plt},
-  {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm_v3},
+  {J2K_MS_PPM, J2K_STATE_MH, opj_j2k_read_ppm},
   {J2K_MS_PPT, J2K_STATE_TPH, opj_j2k_read_ppt},
   {J2K_MS_SOP, 0, 0},
   {J2K_MS_CRG, J2K_STATE_MH, opj_j2k_read_crg},
@@ -1275,7 +1329,7 @@ const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] =
   {J2K_MS_UNK, J2K_STATE_MH | J2K_STATE_TPH, 0}/*opj_j2k_read_unk is directly used*/
 };
 
-void  opj_j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data;
@@ -1291,7 +1345,7 @@ void  opj_j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void  opj_j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data;
@@ -1307,7 +1361,7 @@ void  opj_j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void  opj_j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data;
@@ -1323,7 +1377,7 @@ void  opj_j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data
         }
 }
 
-void  opj_j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data;
@@ -1339,7 +1393,7 @@ void  opj_j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data
         }
 }
 
-void  opj_j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data;
@@ -1355,7 +1409,7 @@ void  opj_j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void  opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data;
@@ -1371,7 +1425,7 @@ void  opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void  opj_j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data;
@@ -1387,7 +1441,7 @@ void  opj_j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data
         }
 }
 
-void  opj_j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
         OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data;
@@ -1403,7 +1457,7 @@ void  opj_j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data
         }
 }
 
-void  opj_j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data;
         OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data;
@@ -1419,7 +1473,7 @@ void  opj_j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void opj_j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void opj_j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data;
         OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data;
@@ -1435,7 +1489,7 @@ void opj_j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void  opj_j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data;
         OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data;
@@ -1451,7 +1505,7 @@ void  opj_j2k_write_float_to_float (const void * p_src_data, void * p_dest_data,
         }
 }
 
-void  opj_j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
+static void  opj_j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
 {
         OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data;
         OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data;
@@ -1477,7 +1531,7 @@ char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){
         return po->str_prog;
 }
 
-OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs,
+static OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs,
                                                         OPJ_UINT32 p_nb_pocs,
                                                         OPJ_UINT32 p_nb_resolutions,
                                                         OPJ_UINT32 p_num_comps,
@@ -1498,7 +1552,6 @@ OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs,
                 opj_event_msg(p_manager , EVT_ERROR, "Not enough memory for checking the poc values.\n");
                 return OPJ_FALSE;
         }
-        memset(packet_array,0,step_l * p_num_layers* sizeof(OPJ_UINT32));
 
         if (p_nb_pocs == 0) {
         opj_free(packet_array);
@@ -1582,7 +1635,7 @@ OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs,
 
 /* ----------------------------------------------------------------------- */
 
-OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno)
+static OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno)
 {
         const OPJ_CHAR *prog = 00;
         OPJ_INT32 i;
@@ -1640,7 +1693,7 @@ OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno)
         return tpnum;
 }
 
-OPJ_BOOL opj_j2k_calculate_tp(  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_calculate_tp(  opj_j2k_t *p_j2k,
                                                         opj_cp_t *cp,
                                                         OPJ_UINT32 * p_nb_tiles,
                                                         opj_image_t *image,
@@ -1718,7 +1771,7 @@ OPJ_BOOL opj_j2k_calculate_tp(  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_soc(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_soc(     opj_j2k_t *p_j2k,
                                                 opj_stream_private_t *p_stream,
                                                     opj_event_mgr_t * p_manager )
 {
@@ -1796,7 +1849,7 @@ static OPJ_BOOL opj_j2k_read_soc(   opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_siz(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_siz(     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager )
 {
@@ -1909,7 +1962,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
         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;
@@ -1939,7 +1992,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
 
         opj_read_bytes(p_header_data,&l_tmp ,2);                                                /* Rsiz (capabilities) */
         p_header_data+=2;
-        l_cp->rsiz = (OPJ_RSIZ_CAPABILITIES) l_tmp;
+        l_cp->rsiz = (OPJ_UINT16) l_tmp;
         opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->x1, 4);   /* Xsiz */
         p_header_data+=4;
         opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->y1, 4);   /* Ysiz */
@@ -1971,8 +2024,9 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
         }
 
         /* 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) */
@@ -1983,7 +2037,15 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
 
         /* testcase 1610.pdf.SIGSEGV.59c.681 */
         if (((OPJ_UINT64)l_image->x1) * ((OPJ_UINT64)l_image->y1) != (l_image->x1 * l_image->y1)) {
-                opj_event_msg(p_manager, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)", l_image->x1, l_image->y1);
+                opj_event_msg(p_manager, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)\n", l_image->x1, l_image->y1);
+                return OPJ_FALSE;
+        }
+
+        /* testcase issue427-illegal-tile-offset.jp2 */
+        l_tx1 = opj_uint_adds(l_cp->tx0, l_cp->tdx); /* manage overflow */
+        l_ty1 = opj_uint_adds(l_cp->ty0, l_cp->tdy); /* manage overflow */
+        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;
         }
 
@@ -2037,7 +2099,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                 return OPJ_FALSE;
         }
 
-        memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t));
         l_img_comp = l_image->comps;
 
         /* Read the component information */
@@ -2166,7 +2227,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                 opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n");
                 return OPJ_FALSE;
         }
-        memset(l_cp->tcps,0,l_nb_tiles*sizeof(opj_tcp_t));
 
 #ifdef USE_JPWL
         if (l_cp->correct) {
@@ -2187,27 +2247,24 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                 opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n");
                 return OPJ_FALSE;
         }
-        memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps ,0,l_image->numcomps*sizeof(opj_tccp_t));
 
         p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records =
-                        (opj_mct_data_t*)opj_malloc(OPJ_J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t));
+                        (opj_mct_data_t*)opj_calloc(OPJ_J2K_MCT_DEFAULT_NB_RECORDS ,sizeof(opj_mct_data_t));
 
         if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records) {
                 opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n");
                 return OPJ_FALSE;
         }
-        memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records,0,OPJ_J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t));
         p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mct_records = OPJ_J2K_MCT_DEFAULT_NB_RECORDS;
 
         p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records =
                         (opj_simple_mcc_decorrelation_data_t*)
-                        opj_malloc(OPJ_J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t));
+                        opj_calloc(OPJ_J2K_MCC_DEFAULT_NB_RECORDS, sizeof(opj_simple_mcc_decorrelation_data_t));
 
         if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records) {
                 opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n");
                 return OPJ_FALSE;
         }
-        memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records,0,OPJ_J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t));
         p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mcc_records = OPJ_J2K_MCC_DEFAULT_NB_RECORDS;
 
         /* set up default dc level shift */
@@ -2219,12 +2276,11 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
 
         l_current_tile_param = l_cp->tcps;
         for     (i = 0; i < l_nb_tiles; ++i) {
-                l_current_tile_param->tccps = (opj_tccp_t*) opj_malloc(l_image->numcomps * sizeof(opj_tccp_t));
+                l_current_tile_param->tccps = (opj_tccp_t*) opj_calloc(l_image->numcomps, sizeof(opj_tccp_t));
                 if (l_current_tile_param->tccps == 00) {
                         opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n");
                         return OPJ_FALSE;
                 }
-                memset(l_current_tile_param->tccps,0,l_image->numcomps * sizeof(opj_tccp_t));
 
                 ++l_current_tile_param;
         }
@@ -2235,7 +2291,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_com(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_com(     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager
                             )
@@ -2309,7 +2365,7 @@ static OPJ_BOOL opj_j2k_read_com (  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_cod(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_cod(     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager )
 {
@@ -2412,7 +2468,14 @@ static OPJ_BOOL opj_j2k_read_cod (  opj_j2k_t *p_j2k,
         l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ?
                                 &l_cp->tcps[p_j2k->m_current_tile_number] :
                                 p_j2k->m_specific_param.m_decoder.m_default_tcp;
-
+       
+        /* Only one COD per tile */
+        if (l_tcp->cod) {
+                opj_event_msg(p_manager, EVT_ERROR, "COD marker already read. No more than one COD marker per tile.\n");
+                return OPJ_FALSE;
+        }
+        l_tcp->cod = 1;
+       
         /* Make sure room is sufficient */
         if (p_header_size < 5) {
                 opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n");
@@ -2421,11 +2484,26 @@ static OPJ_BOOL opj_j2k_read_cod (  opj_j2k_t *p_j2k,
 
         opj_read_bytes(p_header_data,&l_tcp->csty,1);           /* Scod */
         ++p_header_data;
+        /* Make sure we know how to decode this */
+        if ((l_tcp->csty & ~(OPJ_UINT32)(J2K_CP_CSTY_PRT | J2K_CP_CSTY_SOP | J2K_CP_CSTY_EPH)) != 0U) {
+                opj_event_msg(p_manager, EVT_ERROR, "Unknown Scod value in COD marker\n");
+                return OPJ_FALSE;
+        }
         opj_read_bytes(p_header_data,&l_tmp,1);                         /* SGcod (A) */
         ++p_header_data;
         l_tcp->prg = (OPJ_PROG_ORDER) l_tmp;
+        /* Make sure progression order is valid */
+        if (l_tcp->prg > OPJ_CPRL ) {
+                opj_event_msg(p_manager, EVT_ERROR, "Unknown progression order in COD marker\n");
+                l_tcp->prg = OPJ_PROG_UNKNOWN;
+        }
         opj_read_bytes(p_header_data,&l_tcp->numlayers,2);      /* SGcod (B) */
         p_header_data+=2;
+       
+        if ((l_tcp->numlayers < 1U) || (l_tcp->numlayers > 65535U)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Invalid number of layers in COD marker : %d not in range [1-65535]\n", l_tcp->numlayers);
+                return OPJ_FALSE;
+        }
 
         /* If user didn't set a number layer to decode take the max specify in the codestream. */
         if      (l_cp->m_specific_param.m_dec.m_layer) {
@@ -2473,7 +2551,7 @@ static OPJ_BOOL opj_j2k_read_cod (  opj_j2k_t *p_j2k,
 }
 
 #if 0
-OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k,
                                                 OPJ_UINT32 p_comp_no,
                                                 opj_stream_private_t *p_stream,
                                                 opj_event_mgr_t * p_manager )
@@ -2520,7 +2598,7 @@ OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k,
 #endif
 
 #if 0
-void opj_j2k_write_coc_in_memory(   opj_j2k_t *p_j2k,
+static void opj_j2k_write_coc_in_memory(   opj_j2k_t *p_j2k,
                                                 OPJ_UINT32 p_comp_no,
                                                 OPJ_BYTE * p_data,
                                                 OPJ_UINT32 * p_data_written,
@@ -2566,7 +2644,7 @@ void opj_j2k_write_coc_in_memory(   opj_j2k_t *p_j2k,
 }
 #endif
 
-OPJ_UINT32 opj_j2k_get_max_coc_size(opj_j2k_t *p_j2k)
+static OPJ_UINT32 opj_j2k_get_max_coc_size(opj_j2k_t *p_j2k)
 {
         OPJ_UINT32 i,j;
         OPJ_UINT32 l_nb_comp;
@@ -2648,7 +2726,7 @@ static OPJ_BOOL opj_j2k_read_coc (  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_qcd(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_qcd(     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager
                             )
@@ -2739,7 +2817,7 @@ static OPJ_BOOL opj_j2k_read_qcd (  opj_j2k_t *p_j2k,
 }
 
 #if 0
-OPJ_BOOL opj_j2k_write_qcc(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_qcc(     opj_j2k_t *p_j2k,
                                                 OPJ_UINT32 p_comp_no,
                                                 opj_stream_private_t *p_stream,
                                                 opj_event_mgr_t * p_manager
@@ -2780,7 +2858,7 @@ OPJ_BOOL opj_j2k_write_qcc(     opj_j2k_t *p_j2k,
 #endif
 
 #if 0
-void opj_j2k_write_qcc_in_memory(   opj_j2k_t *p_j2k,
+static void opj_j2k_write_qcc_in_memory(   opj_j2k_t *p_j2k,
                                                                 OPJ_UINT32 p_comp_no,
                                                                 OPJ_BYTE * p_data,
                                                                 OPJ_UINT32 * p_data_written,
@@ -2830,7 +2908,7 @@ void opj_j2k_write_qcc_in_memory(   opj_j2k_t *p_j2k,
 }
 #endif
 
-OPJ_UINT32 opj_j2k_get_max_qcc_size (opj_j2k_t *p_j2k)
+static OPJ_UINT32 opj_j2k_get_max_qcc_size (opj_j2k_t *p_j2k)
 {
         return opj_j2k_get_max_coc_size(p_j2k);
 }
@@ -2922,7 +3000,7 @@ static OPJ_BOOL opj_j2k_read_qcc(   opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_poc(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_poc(     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager
                             )
@@ -2973,7 +3051,7 @@ OPJ_BOOL opj_j2k_write_poc(     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-void opj_j2k_write_poc_in_memory(   opj_j2k_t *p_j2k,
+static void opj_j2k_write_poc_in_memory(   opj_j2k_t *p_j2k,
                                                                 OPJ_BYTE * p_data,
                                                                 OPJ_UINT32 * p_data_written,
                                                                 opj_event_mgr_t * p_manager
@@ -3048,7 +3126,7 @@ void opj_j2k_write_poc_in_memory(   opj_j2k_t *p_j2k,
         *p_data_written = l_poc_size;
 }
 
-OPJ_UINT32 opj_j2k_get_max_poc_size(opj_j2k_t *p_j2k)
+static OPJ_UINT32 opj_j2k_get_max_poc_size(opj_j2k_t *p_j2k)
 {
         opj_tcp_t * l_tcp = 00;
         OPJ_UINT32 l_nb_tiles = 0;
@@ -3068,7 +3146,7 @@ OPJ_UINT32 opj_j2k_get_max_poc_size(opj_j2k_t *p_j2k)
         return 4 + 9 * l_max_poc;
 }
 
-OPJ_UINT32 opj_j2k_get_max_toc_size (opj_j2k_t *p_j2k)
+static OPJ_UINT32 opj_j2k_get_max_toc_size (opj_j2k_t *p_j2k)
 {
         OPJ_UINT32 i;
         OPJ_UINT32 l_nb_tiles;
@@ -3087,7 +3165,7 @@ OPJ_UINT32 opj_j2k_get_max_toc_size (opj_j2k_t *p_j2k)
         return 12 * l_max;
 }
 
-OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k)
+static OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k)
 {
         OPJ_UINT32 l_nb_bytes = 0;
         OPJ_UINT32 l_nb_comps;
@@ -3096,7 +3174,7 @@ OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k)
         l_nb_comps = p_j2k->m_private_image->numcomps - 1;
         l_nb_bytes += opj_j2k_get_max_toc_size(p_j2k);
 
-        if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == 0) {
+        if (!(OPJ_IS_CINEMA(p_j2k->m_cp.rsiz))) {
                 l_coc_bytes = opj_j2k_get_max_coc_size(p_j2k);
                 l_nb_bytes += l_nb_comps * l_coc_bytes;
 
@@ -3163,6 +3241,11 @@ static OPJ_BOOL opj_j2k_read_poc (  opj_j2k_t *p_j2k,
         l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0;
         l_current_poc_nb += l_old_poc_nb;
 
+        if(l_current_poc_nb >= 32)
+          {
+          opj_event_msg(p_manager, EVT_ERROR, "Too many POCs %d\n", l_current_poc_nb);
+          return OPJ_FALSE;
+          }
         assert(l_current_poc_nb < 32);
 
         /* now poc is in use.*/
@@ -3175,6 +3258,8 @@ static OPJ_BOOL opj_j2k_read_poc (  opj_j2k_t *p_j2k,
                 opj_read_bytes(p_header_data,&(l_current_poc->compno0),l_comp_room);    /* CSpoc_i */
                 p_header_data+=l_comp_room;
                 opj_read_bytes(p_header_data,&(l_current_poc->layno1),2);                               /* LYEpoc_i */
+                /* make sure layer end is in acceptable bounds */
+                l_current_poc->layno1 = opj_uint_min(l_current_poc->layno1, l_tcp->numlayers);
                 p_header_data+=2;
                 opj_read_bytes(p_header_data,&(l_current_poc->resno1),1);                               /* REpoc_i */
                 ++p_header_data;
@@ -3410,326 +3495,220 @@ static OPJ_BOOL opj_j2k_read_plt (  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-#if 0
-OPJ_BOOL j2k_read_ppm_v2 (
-                                                opj_j2k_t *p_j2k,
-                                                OPJ_BYTE * p_header_data,
-                                                OPJ_UINT32 p_header_size,
-                                                struct opj_event_mgr * p_manager
-                                        )
-{
-
-        opj_cp_t *l_cp = 00;
-        OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm;
-
-        /* preconditions */
-        assert(p_header_data != 00);
-        assert(p_j2k != 00);
-        assert(p_manager != 00);
-
-        if (p_header_size < 1) {
-                opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
-                return OPJ_FALSE;
-        }
-
-        l_cp = &(p_j2k->m_cp);
-        l_cp->ppm = 1;
-
-        opj_read_bytes(p_header_data,&l_Z_ppm,1);               /* Z_ppm */
-        ++p_header_data;
-        --p_header_size;
-
-        /* First PPM marker */
-        if (l_Z_ppm == 0) {
-                if (p_header_size < 4) {
-                        opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
-                        return OPJ_FALSE;
-                }
-
-                opj_read_bytes(p_header_data,&l_N_ppm,4);               /* N_ppm */
-                p_header_data+=4;
-                p_header_size-=4;
-
-                /* First PPM marker: Initialization */
-                l_cp->ppm_len = l_N_ppm;
-                l_cp->ppm_data_size = 0;
-
-                l_cp->ppm_buffer = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len);
-                if (l_cp->ppm_buffer == 00) {
-                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n");
-                        return OPJ_FALSE;
-                }
-                memset(l_cp->ppm_buffer,0,l_cp->ppm_len);
-
-                l_cp->ppm_data = l_cp->ppm_buffer;
-        }
-
-        while (1) {
-                if (l_cp->ppm_data_size == l_cp->ppm_len) {
-                        if (p_header_size >= 4) {
-                                /* read a N_ppm */
-                                opj_read_bytes(p_header_data,&l_N_ppm,4);               /* N_ppm */
-                                p_header_data+=4;
-                                p_header_size-=4;
-                                l_cp->ppm_len += l_N_ppm ;
-
-                                OPJ_BYTE *new_ppm_buffer = (OPJ_BYTE *) opj_realloc(l_cp->ppm_buffer, l_cp->ppm_len);
-                                if (! new_ppm_buffer) {
-                                        opj_free(l_cp->ppm_buffer);
-                                        l_cp->ppm_buffer = NULL;
-                                        l_cp->ppm_len = 0;
-                                        l_cp->ppm_data = NULL;
-                                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n");
-                                        return OPJ_FALSE;
-                                }
-                                l_cp->ppm_buffer = new_ppm_buffer;
-                                memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm);
-                                l_cp->ppm_data = l_cp->ppm_buffer;
-                        }
-                        else {
-                                return OPJ_FALSE;
-                        }
-                }
-
-                l_remaining_data = l_cp->ppm_len - l_cp->ppm_data_size;
-
-                if (l_remaining_data <= p_header_size) {
-                        /* we must store less information than available in the packet */
-                        memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , l_remaining_data);
-                        l_cp->ppm_data_size = l_cp->ppm_len;
-                        p_header_size -= l_remaining_data;
-                        p_header_data += l_remaining_data;
-                }
-                else {
-                        memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , p_header_size);
-                        l_cp->ppm_data_size += p_header_size;
-                        p_header_data += p_header_size;
-                        p_header_size = 0;
-                        break;
-                }
-        }
+/**
+ * Reads a PPM marker (Packed packet headers, main header)
+ *
+ * @param       p_header_data   the data contained in the POC box.
+ * @param       p_j2k                   the jpeg2000 codec.
+ * @param       p_header_size   the size of the data contained in the POC marker.
+ * @param       p_manager               the user event manager.
+ */
 
-        return OPJ_TRUE;
+static OPJ_BOOL opj_j2k_read_ppm (
+                                                                                                                                       opj_j2k_t *p_j2k,
+                                                                                                                                       OPJ_BYTE * p_header_data,
+                                                                                                                                       OPJ_UINT32 p_header_size,
+                                                                                                                                       opj_event_mgr_t * p_manager )
+{
+       opj_cp_t *l_cp = 00;
+       OPJ_UINT32 l_Z_ppm;
+       
+       /* preconditions */
+       assert(p_header_data != 00);
+       assert(p_j2k != 00);
+       assert(p_manager != 00);
+       
+       /* We need to have the Z_ppm element + 1 byte of Nppm/Ippm at minimum */
+       if (p_header_size < 2) {
+               opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
+               return OPJ_FALSE;
+       }
+       
+       l_cp = &(p_j2k->m_cp);
+       l_cp->ppm = 1;
+       
+       opj_read_bytes(p_header_data,&l_Z_ppm,1);               /* Z_ppm */
+       ++p_header_data;
+       --p_header_size;
+       
+       /* check allocation needed */
+       if (l_cp->ppm_markers == NULL) { /* first PPM marker */
+               OPJ_UINT32 l_newCount = l_Z_ppm + 1U; /* can't overflow, l_Z_ppm is UINT8 */
+               assert(l_cp->ppm_markers_count == 0U);
+               
+               l_cp->ppm_markers = (opj_ppx *) opj_calloc(l_newCount, sizeof(opj_ppx));
+               if (l_cp->ppm_markers == NULL) {
+                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n");
+                       return OPJ_FALSE;
+               }
+               l_cp->ppm_markers_count = l_newCount;
+       } else if (l_cp->ppm_markers_count <= l_Z_ppm) {
+               OPJ_UINT32 l_newCount = l_Z_ppm + 1U; /* can't overflow, l_Z_ppm is UINT8 */
+               opj_ppx *new_ppm_markers;
+               new_ppm_markers = (opj_ppx *) opj_realloc(l_cp->ppm_markers, l_newCount * sizeof(opj_ppx));
+               if (new_ppm_markers == NULL) {
+                       /* clean up to be done on l_cp destruction */
+                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n");
+                       return OPJ_FALSE;
+               }
+               l_cp->ppm_markers = new_ppm_markers;
+               memset(l_cp->ppm_markers + l_cp->ppm_markers_count, 0, (l_newCount - l_cp->ppm_markers_count) * sizeof(opj_ppx));
+               l_cp->ppm_markers_count = l_newCount;
+       }
+       
+       if (l_cp->ppm_markers[l_Z_ppm].m_data != NULL) {
+               /* clean up to be done on l_cp destruction */
+               opj_event_msg(p_manager, EVT_ERROR, "Zppm %u already read\n", l_Z_ppm);
+               return OPJ_FALSE;
+       }
+       
+       l_cp->ppm_markers[l_Z_ppm].m_data = opj_malloc(p_header_size);
+       if (l_cp->ppm_markers[l_Z_ppm].m_data == NULL) {
+               /* clean up to be done on l_cp destruction */
+               opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n");
+               return OPJ_FALSE;
+       }
+       l_cp->ppm_markers[l_Z_ppm].m_data_size = p_header_size;
+       memcpy(l_cp->ppm_markers[l_Z_ppm].m_data, p_header_data, p_header_size);
+
+       return OPJ_TRUE;
 }
-#endif
-
-OPJ_BOOL j2k_read_ppm_v3 (
-                                                opj_j2k_t *p_j2k,
-                                                OPJ_BYTE * p_header_data,
-                                                OPJ_UINT32 p_header_size,
-                                                struct opj_event_mgr * p_manager
-                                        )
-{
-        opj_cp_t *l_cp = 00;
-        OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm;
-
-        /* preconditions */
-        assert(p_header_data != 00);
-        assert(p_j2k != 00);
-        assert(p_manager != 00);
-
-        /* Minimum size of PPM marker is equal to the size of Zppm element */
-        if (p_header_size < 1) {
-                opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
-                return OPJ_FALSE;
-        }
-
-        l_cp = &(p_j2k->m_cp);
-        l_cp->ppm = 1;
-
-        opj_read_bytes(p_header_data,&l_Z_ppm,1);               /* Z_ppm */
-        ++p_header_data;
-        --p_header_size;
-
-        /* First PPM marker */
-        if (l_Z_ppm == 0) {
-                /* 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");
-                        return OPJ_FALSE;
-                }
-
-                opj_read_bytes(p_header_data,&l_N_ppm,4);               /* First N_ppm */
-                p_header_data+=4;
-                p_header_size-=4;
-
-                /* First PPM marker: Initialization */
-                l_cp->ppm_len = l_N_ppm;
-                l_cp->ppm_data_read = 0;
-
-                l_cp->ppm_data = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len);
-                l_cp->ppm_buffer = l_cp->ppm_data;
-                if (l_cp->ppm_data == 00) {
-                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read ppm marker\n");
-                        return OPJ_FALSE;
-                }
-                memset(l_cp->ppm_data,0,l_cp->ppm_len);
-
-                l_cp->ppm_data_current = l_cp->ppm_data;
-
-                /*l_cp->ppm_data = l_cp->ppm_buffer;*/
-        }
-        else {
-                if (p_header_size < 4) {
-                        opj_event_msg(p_manager, EVT_WARNING, "Empty PPM marker\n");
-                        return OPJ_TRUE;
-                }
-                else {
-                        /* Uncompleted Ippm series in the previous PPM marker?*/
-                        if (l_cp->ppm_data_read < l_cp->ppm_len) {
-                                /* Get the place where add the remaining Ippm series*/
-                                l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_data_read]);
-                                l_N_ppm = l_cp->ppm_len - l_cp->ppm_data_read;
-                        }
-                        else {
-                                OPJ_BYTE *new_ppm_data;
-                                opj_read_bytes(p_header_data,&l_N_ppm,4);               /* First N_ppm */
-                                p_header_data+=4;
-                                p_header_size-=4;
-
-                                /* 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");
-                                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);
-                                        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 Ippm series\n");
-                                        return OPJ_FALSE;
-                                }
-                                l_cp->ppm_data = new_ppm_data;
-                                l_cp->ppm_buffer = l_cp->ppm_data;
-
-                                /* Keep the position of the place where concatenate the new series*/
-                                l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]);
-                                l_cp->ppm_len += l_N_ppm;
-                        }
-                }
-        }
-
-        l_remaining_data = p_header_size;
-
-        while (l_remaining_data >= l_N_ppm) {
-                /* read a complete Ippm series*/
-                memcpy(l_cp->ppm_data_current, p_header_data, l_N_ppm);
-                p_header_size -= l_N_ppm;
-                p_header_data += l_N_ppm;
-
-                l_cp->ppm_data_read += l_N_ppm; /* Increase the number of data read*/
-
-                if (p_header_size)
-                {
-                        opj_read_bytes(p_header_data,&l_N_ppm,4);               /* N_ppm^i */
-                        p_header_data+=4;
-                        p_header_size-=4;
-                }
-                else {
-                        l_remaining_data = p_header_size;
-                        break;
-                }
-
-                l_remaining_data = p_header_size;
-
-                /* Next Ippm series is a complete series ?*/
-                if (l_remaining_data > l_N_ppm) {
-                        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");
-                        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);
-                                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;
-                        }
-                        l_cp->ppm_data = new_ppm_data;
-                        l_cp->ppm_buffer = l_cp->ppm_data;
-
-                        /* Keep the position of the place where concatenate the new series */
-                        l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]);
-                        l_cp->ppm_len += l_N_ppm;
-                }
-
-        }
-
-        /* Need to read an incomplete Ippm series*/
-        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");
-                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);
-                        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 (incomplete) Ippm series\n");
-                        return OPJ_FALSE;
-                }
-                l_cp->ppm_data = new_ppm_data;
-                l_cp->ppm_buffer = l_cp->ppm_data;
-
-                /* Keep the position of the place where concatenate the new series*/
-                l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]);
-                l_cp->ppm_len += l_N_ppm;
-
-                /* Read incomplete Ippm series*/
-                memcpy(l_cp->ppm_data_current, p_header_data, l_remaining_data);
-                p_header_size -= l_remaining_data;
-                p_header_data += l_remaining_data;
-
-                l_cp->ppm_data_read += l_remaining_data; /* Increase the number of data read*/
-        }
-
-#ifdef CLEAN_MSD
-
-                if (l_cp->ppm_data_size == l_cp->ppm_len) {
-                        if (p_header_size >= 4) {
-                                /* read a N_ppm*/
-                                opj_read_bytes(p_header_data,&l_N_ppm,4);               /* N_ppm */
-                                p_header_data+=4;
-                                p_header_size-=4;
-                                l_cp->ppm_len += l_N_ppm ;
-
-                                OPJ_BYTE *new_ppm_buffer = (OPJ_BYTE *) opj_realloc(l_cp->ppm_buffer, l_cp->ppm_len);
-                                if (! new_ppm_buffer) {
-                                        opj_free(l_cp->ppm_buffer);
-                                        l_cp->ppm_buffer = NULL;
-                                        l_cp->ppm_len = 0;
-                                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read ppm marker\n");
-                                        return OPJ_FALSE;
-                                }
-                                l_cp->ppm_buffer = new_ppm_buffer;
-                                memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm);
-
-                                l_cp->ppm_data = l_cp->ppm_buffer;
-                        }
-                        else {
-                                return OPJ_FALSE;
-                        }
-                }
-
-                l_remaining_data = l_cp->ppm_len - l_cp->ppm_data_size;
 
-                if (l_remaining_data <= p_header_size) {
-                        /* we must store less information than available in the packet */
-                        memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , l_remaining_data);
-                        l_cp->ppm_data_size = l_cp->ppm_len;
-                        p_header_size -= l_remaining_data;
-                        p_header_data += l_remaining_data;
-                }
-                else {
-                        memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , p_header_size);
-                        l_cp->ppm_data_size += p_header_size;
-                        p_header_data += p_header_size;
-                        p_header_size = 0;
-                        break;
-                }
-        }
-#endif
-        return OPJ_TRUE;
+/**
+ * Merges all PPM markers read (Packed headers, main header)
+ *
+ * @param       p_cp      main coding parameters.
+ * @param       p_manager the user event manager.
+ */
+static OPJ_BOOL opj_j2k_merge_ppm ( opj_cp_t *p_cp, opj_event_mgr_t * p_manager )
+{
+       OPJ_UINT32 i, l_ppm_data_size, l_N_ppm_remaining;
+       
+       /* preconditions */
+       assert(p_cp != 00);
+       assert(p_manager != 00);
+       assert(p_cp->ppm_buffer == NULL);
+       
+       if (p_cp->ppm == 0U) {
+               return OPJ_TRUE;
+       }
+       
+       l_ppm_data_size = 0U;
+       l_N_ppm_remaining = 0U;
+       for (i = 0U; i < p_cp->ppm_markers_count; ++i) {
+               if (p_cp->ppm_markers[i].m_data != NULL) { /* standard doesn't seem to require contiguous Zppm */
+                       OPJ_UINT32 l_N_ppm;
+                       OPJ_UINT32 l_data_size = p_cp->ppm_markers[i].m_data_size;
+                       const OPJ_BYTE* l_data = p_cp->ppm_markers[i].m_data;
+                       
+                       if (l_N_ppm_remaining >= l_data_size) {
+                               l_N_ppm_remaining -= l_data_size;
+                               l_data_size = 0U;
+                       } else {
+                               l_data += l_N_ppm_remaining;
+                               l_data_size -= l_N_ppm_remaining;
+                               l_N_ppm_remaining = 0U;
+                       }
+                       
+                       if (l_data_size > 0U) {
+                               do
+                               {
+                                       /* read Nppm */
+                                       if (l_data_size < 4U) {
+                                               /* clean up to be done on l_cp destruction */
+                                               opj_event_msg(p_manager, EVT_ERROR, "Not enough bytes to read Nppm\n");
+                                               return OPJ_FALSE;
+                                       }
+                                       opj_read_bytes(l_data, &l_N_ppm, 4);
+                                       l_data+=4;
+                                       l_data_size-=4;
+                                       l_ppm_data_size += l_N_ppm; /* can't overflow, max 256 markers of max 65536 bytes, that is when PPM markers are not corrupted which is checked elsewhere */
+                                       
+                                       if (l_data_size >= l_N_ppm) {
+                                               l_data_size -= l_N_ppm;
+                                               l_data += l_N_ppm;
+                                       } else {
+                                               l_N_ppm_remaining = l_N_ppm - l_data_size;
+                                               l_data_size = 0U;
+                                       }
+                               } while (l_data_size > 0U);
+                       }
+               }
+       }
+       
+       if (l_N_ppm_remaining != 0U) {
+               /* clean up to be done on l_cp destruction */
+               opj_event_msg(p_manager, EVT_ERROR, "Corrupted PPM markers\n");
+               return OPJ_FALSE;
+       }
+       
+       p_cp->ppm_buffer = (OPJ_BYTE *) opj_malloc(l_ppm_data_size);
+       if (p_cp->ppm_buffer == 00) {
+               opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n");
+               return OPJ_FALSE;
+       }
+       p_cp->ppm_len = l_ppm_data_size;
+       l_ppm_data_size = 0U;
+       l_N_ppm_remaining = 0U;
+       for (i = 0U; i < p_cp->ppm_markers_count; ++i) {
+               if (p_cp->ppm_markers[i].m_data != NULL) { /* standard doesn't seem to require contiguous Zppm */
+                       OPJ_UINT32 l_N_ppm;
+                       OPJ_UINT32 l_data_size = p_cp->ppm_markers[i].m_data_size;
+                       const OPJ_BYTE* l_data = p_cp->ppm_markers[i].m_data;
+                       
+                       if (l_N_ppm_remaining >= l_data_size) {
+                               memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_data_size);
+                               l_ppm_data_size += l_data_size;
+                               l_N_ppm_remaining -= l_data_size;
+                               l_data_size = 0U;
+                       } else {
+                               memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_N_ppm_remaining);
+                               l_ppm_data_size += l_N_ppm_remaining;
+                               l_data += l_N_ppm_remaining;
+                               l_data_size -= l_N_ppm_remaining;
+                               l_N_ppm_remaining = 0U;
+                       }
+
+                       if (l_data_size > 0U) {
+                               do
+                               {
+                                       /* read Nppm */
+                                       if (l_data_size < 4U) {
+                                               /* clean up to be done on l_cp destruction */
+                                               opj_event_msg(p_manager, EVT_ERROR, "Not enough bytes to read Nppm\n");
+                                               return OPJ_FALSE;
+                                       }
+                                       opj_read_bytes(l_data, &l_N_ppm, 4);
+                                       l_data+=4;
+                                       l_data_size-=4;
+                                       
+                                       if (l_data_size >= l_N_ppm) {
+                                               memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_N_ppm);
+                                               l_ppm_data_size += l_N_ppm;
+                                               l_data_size -= l_N_ppm;
+                                               l_data += l_N_ppm;
+                                       } else {
+                                               memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_data_size);
+                                               l_ppm_data_size += l_data_size;
+                                               l_N_ppm_remaining = l_N_ppm - l_data_size;
+                                               l_data_size = 0U;
+                                       }
+                               } while (l_data_size > 0U);
+                       }
+                       opj_free(p_cp->ppm_markers[i].m_data);
+                       p_cp->ppm_markers[i].m_data = NULL;
+                       p_cp->ppm_markers[i].m_data_size = 0U;
+               }
+       }
+       
+       p_cp->ppm_data = p_cp->ppm_buffer;
+       p_cp->ppm_data_size = p_cp->ppm_len;
+       
+       p_cp->ppm_markers_count = 0U;
+       opj_free(p_cp->ppm_markers);
+       p_cp->ppm_markers = NULL;
+       
+       return OPJ_TRUE;
 }
 
 /**
@@ -3746,76 +3725,127 @@ static OPJ_BOOL opj_j2k_read_ppt (  opj_j2k_t *p_j2k,
                                     opj_event_mgr_t * p_manager
                                     )
 {
-        opj_cp_t *l_cp = 00;
-        opj_tcp_t *l_tcp = 00;
-        OPJ_UINT32 l_Z_ppt;
-
-        /* preconditions */
-        assert(p_header_data != 00);
-        assert(p_j2k != 00);
-        assert(p_manager != 00);
-
-        /* We need to have the Z_ppt element at minimum */
-        if (p_header_size < 1) {
-                opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker\n");
-                return OPJ_FALSE;
-        }
-
-        l_cp = &(p_j2k->m_cp);
-        if (l_cp->ppm){
-                opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker: packet header have been previously found in the main header (PPM marker).\n");
-                return OPJ_FALSE;
-        }
-
-        l_tcp = &(l_cp->tcps[p_j2k->m_current_tile_number]);
-        l_tcp->ppt = 1;
-
-        opj_read_bytes(p_header_data,&l_Z_ppt,1);               /* Z_ppt */
-        ++p_header_data;
-        --p_header_size;
-
-        /* Allocate buffer to read the packet header */
-        if (l_Z_ppt == 0) {
-                /* First PPT marker */
-                l_tcp->ppt_data_size = 0;
-                l_tcp->ppt_len = p_header_size;
-
-                l_tcp->ppt_buffer = (OPJ_BYTE *) opj_calloc(l_tcp->ppt_len, sizeof(OPJ_BYTE) );
-                if (l_tcp->ppt_buffer == 00) {
-                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
-                        return OPJ_FALSE;
-                }
-                l_tcp->ppt_data = l_tcp->ppt_buffer;
-
-                /* memset(l_tcp->ppt_buffer,0,l_tcp->ppt_len); */
-        }
-        else {
-                OPJ_BYTE *new_ppt_buffer;
-                l_tcp->ppt_len += p_header_size;
-
-                new_ppt_buffer = (OPJ_BYTE *) opj_realloc(l_tcp->ppt_buffer, l_tcp->ppt_len);
-                if (! new_ppt_buffer) {
-                        opj_free(l_tcp->ppt_buffer);
-                        l_tcp->ppt_buffer = NULL;
-                        l_tcp->ppt_len = 0;
-                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
-                        return OPJ_FALSE;
-                }
-                l_tcp->ppt_buffer = new_ppt_buffer;
-                l_tcp->ppt_data = l_tcp->ppt_buffer;
-
-                memset(l_tcp->ppt_buffer+l_tcp->ppt_data_size,0,p_header_size);
-        }
-
-        /* Read packet header from buffer */
-        memcpy(l_tcp->ppt_buffer+l_tcp->ppt_data_size,p_header_data,p_header_size);
-
-        l_tcp->ppt_data_size += p_header_size;
-
-        return OPJ_TRUE;
+       opj_cp_t *l_cp = 00;
+       opj_tcp_t *l_tcp = 00;
+       OPJ_UINT32 l_Z_ppt;
+
+       /* preconditions */
+       assert(p_header_data != 00);
+       assert(p_j2k != 00);
+       assert(p_manager != 00);
+
+       /* We need to have the Z_ppt element + 1 byte of Ippt at minimum */
+       if (p_header_size < 2) {
+               opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker\n");
+               return OPJ_FALSE;
+       }
+
+       l_cp = &(p_j2k->m_cp);
+       if (l_cp->ppm){
+               opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker: packet header have been previously found in the main header (PPM marker).\n");
+               return OPJ_FALSE;
+       }
+
+       l_tcp = &(l_cp->tcps[p_j2k->m_current_tile_number]);
+       l_tcp->ppt = 1;
+
+       opj_read_bytes(p_header_data,&l_Z_ppt,1);               /* Z_ppt */
+       ++p_header_data;
+       --p_header_size;
+       
+       /* check allocation needed */
+       if (l_tcp->ppt_markers == NULL) { /* first PPT marker */
+               OPJ_UINT32 l_newCount = l_Z_ppt + 1U; /* can't overflow, l_Z_ppt is UINT8 */
+               assert(l_tcp->ppt_markers_count == 0U);
+               
+               l_tcp->ppt_markers = (opj_ppx *) opj_calloc(l_newCount, sizeof(opj_ppx));
+               if (l_tcp->ppt_markers == NULL) {
+                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
+                       return OPJ_FALSE;
+               }
+               l_tcp->ppt_markers_count = l_newCount;
+       } else if (l_tcp->ppt_markers_count <= l_Z_ppt) {
+               OPJ_UINT32 l_newCount = l_Z_ppt + 1U; /* can't overflow, l_Z_ppt is UINT8 */
+               opj_ppx *new_ppt_markers;
+               new_ppt_markers = (opj_ppx *) opj_realloc(l_tcp->ppt_markers, l_newCount * sizeof(opj_ppx));
+               if (new_ppt_markers == NULL) {
+                       /* clean up to be done on l_tcp destruction */
+                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
+                       return OPJ_FALSE;
+               }
+               l_tcp->ppt_markers = new_ppt_markers;
+               memset(l_tcp->ppt_markers + l_tcp->ppt_markers_count, 0, (l_newCount - l_tcp->ppt_markers_count) * sizeof(opj_ppx));
+               l_tcp->ppt_markers_count = l_newCount;
+       }
+       
+       if (l_tcp->ppt_markers[l_Z_ppt].m_data != NULL) {
+               /* clean up to be done on l_tcp destruction */
+               opj_event_msg(p_manager, EVT_ERROR, "Zppt %u already read\n", l_Z_ppt);
+               return OPJ_FALSE;
+       }
+       
+       l_tcp->ppt_markers[l_Z_ppt].m_data = opj_malloc(p_header_size);
+       if (l_tcp->ppt_markers[l_Z_ppt].m_data == NULL) {
+               /* clean up to be done on l_tcp destruction */
+               opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
+               return OPJ_FALSE;
+       }
+       l_tcp->ppt_markers[l_Z_ppt].m_data_size = p_header_size;
+       memcpy(l_tcp->ppt_markers[l_Z_ppt].m_data, p_header_data, p_header_size);
+       return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_tlm(     opj_j2k_t *p_j2k,
+/**
+ * Merges all PPT markers read (Packed packet headers, tile-part header)
+ *
+ * @param       p_tcp   the tile.
+ * @param       p_manager               the user event manager.
+ */
+static OPJ_BOOL opj_j2k_merge_ppt(opj_tcp_t *p_tcp, opj_event_mgr_t * p_manager)
+{
+       OPJ_UINT32 i, l_ppt_data_size;
+       /* preconditions */
+       assert(p_tcp != 00);
+       assert(p_manager != 00);
+       assert(p_tcp->ppt_buffer == NULL);
+       
+       if (p_tcp->ppt == 0U) {
+               return OPJ_TRUE;
+       }
+       
+       l_ppt_data_size = 0U;
+       for (i = 0U; i < p_tcp->ppt_markers_count; ++i) {
+               l_ppt_data_size += p_tcp->ppt_markers[i].m_data_size; /* can't overflow, max 256 markers of max 65536 bytes */
+       }
+       
+       p_tcp->ppt_buffer = (OPJ_BYTE *) opj_malloc(l_ppt_data_size);
+       if (p_tcp->ppt_buffer == 00) {
+               opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
+               return OPJ_FALSE;
+       }
+       p_tcp->ppt_len = l_ppt_data_size;
+       l_ppt_data_size = 0U;
+       for (i = 0U; i < p_tcp->ppt_markers_count; ++i) {
+               if (p_tcp->ppt_markers[i].m_data != NULL) { /* standard doesn't seem to require contiguous Zppt */
+                       memcpy(p_tcp->ppt_buffer + l_ppt_data_size, p_tcp->ppt_markers[i].m_data, p_tcp->ppt_markers[i].m_data_size);
+                       l_ppt_data_size += p_tcp->ppt_markers[i].m_data_size; /* can't overflow, max 256 markers of max 65536 bytes */
+                       
+                       opj_free(p_tcp->ppt_markers[i].m_data);
+                       p_tcp->ppt_markers[i].m_data = NULL;
+                       p_tcp->ppt_markers[i].m_data_size = 0U;
+               }
+       }
+       
+       p_tcp->ppt_markers_count = 0U;
+       opj_free(p_tcp->ppt_markers);
+       p_tcp->ppt_markers = NULL;
+       
+       p_tcp->ppt_data = p_tcp->ppt_buffer;
+       p_tcp->ppt_data_size = p_tcp->ppt_len;
+       return OPJ_TRUE;
+}
+
+static OPJ_BOOL opj_j2k_write_tlm(     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager
                             )
@@ -3869,7 +3899,7 @@ OPJ_BOOL opj_j2k_write_tlm(     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_sot(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_sot(     opj_j2k_t *p_j2k,
                                                         OPJ_BYTE * p_data,
                                                         OPJ_UINT32 * p_data_written,
                                                         const opj_stream_private_t *p_stream,
@@ -3913,7 +3943,36 @@ OPJ_BOOL opj_j2k_write_sot(     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
+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;
+}
+
+static OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                             OPJ_BYTE * p_header_data,
                             OPJ_UINT32 p_header_size,
                             opj_event_mgr_t * p_manager )
@@ -3925,19 +3984,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) {
@@ -3980,9 +4036,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) )
         {
@@ -4025,13 +4078,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) {
@@ -4098,6 +4146,10 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                                 if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) {
                                         p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index =
                                                 (opj_tp_index_t*)opj_calloc(l_num_parts, sizeof(opj_tp_index_t));
+                                        if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) {
+                                                opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n");
+                                                return OPJ_FALSE;
+                                                                                                                                                               }
                                 }
                                 else {
                                         opj_tp_index_t *new_tp_index = (opj_tp_index_t *) opj_realloc(
@@ -4105,7 +4157,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                                         if (! new_tp_index) {
                                                 opj_free(p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index);
                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = NULL;
-                                                opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
+                                                opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n");
                                                 return OPJ_FALSE;
                                         }
                                         p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = new_tp_index;
@@ -4119,6 +4171,11 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index =
                                                         (opj_tp_index_t*)opj_calloc( p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps,
                                                                         sizeof(opj_tp_index_t));
+                                                                                                                                                                                               if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) {
+                                                        p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = 0;
+                                                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n");
+                                                        return OPJ_FALSE;
+                                                                                                                                                                       }
                                         }
 
                                         if ( l_current_part >= p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps ){
@@ -4131,7 +4188,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                                                         opj_free(p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index);
                                                         p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = NULL;
                                                         p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = 0;
-                                                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
+                                                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n");
                                                         return OPJ_FALSE;
                                                 }
                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = new_tp_index;
@@ -4172,7 +4229,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                 return OPJ_TRUE;
         }
 
-OPJ_BOOL opj_j2k_write_sod(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_sod(     opj_j2k_t *p_j2k,
                                                         opj_tcd_t * p_tile_coder,
                                                         OPJ_BYTE * p_data,
                                                         OPJ_UINT32 * p_data_written,
@@ -4246,7 +4303,7 @@ OPJ_BOOL opj_j2k_write_sod(     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
                            opj_stream_private_t *p_stream,
                                                    opj_event_mgr_t * p_manager
                            )
@@ -4286,6 +4343,12 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
 
         /* Patch to support new PHR data */
         if (p_j2k->m_specific_param.m_decoder.m_sot_length) {
+            /* If we are here, we'll try to read the data after allocation */
+            /* Check enough bytes left in stream before allocation */
+            if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n");
+                return OPJ_FALSE;
+            }
             if (! *l_current_data) {
                 /* LH: oddly enough, in this path, l_tile_len!=0.
                  * TODO: If this was consistant, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...).
@@ -4361,7 +4424,7 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
- OPJ_BOOL opj_j2k_write_rgn(opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_rgn(opj_j2k_t *p_j2k,
                             OPJ_UINT32 p_tile_no,
                             OPJ_UINT32 p_comp_no,
                             OPJ_UINT32 nb_comps,
@@ -4418,7 +4481,7 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_eoc(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_eoc(     opj_j2k_t *p_j2k,
                             opj_stream_private_t *p_stream,
                             opj_event_mgr_t * p_manager
                             )
@@ -4528,18 +4591,18 @@ static OPJ_BOOL opj_j2k_read_rgn (opj_j2k_t *p_j2k,
 
 }
 
-OPJ_FLOAT32 opj_j2k_get_tp_stride (opj_tcp_t * p_tcp)
+static OPJ_FLOAT32 opj_j2k_get_tp_stride (opj_tcp_t * p_tcp)
 {
         return (OPJ_FLOAT32) ((p_tcp->m_nb_tile_parts - 1) * 14);
 }
 
-OPJ_FLOAT32 opj_j2k_get_default_stride (opj_tcp_t * p_tcp)
+static OPJ_FLOAT32 opj_j2k_get_default_stride (opj_tcp_t * p_tcp)
 {
     (void)p_tcp;
     return 0;
 }
 
-OPJ_BOOL opj_j2k_update_rates(  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_update_rates(  opj_j2k_t *p_j2k,
                                                             opj_stream_private_t *p_stream,
                                                             opj_event_mgr_t * p_manager )
 {
@@ -4687,7 +4750,7 @@ OPJ_BOOL opj_j2k_update_rates(  opj_j2k_t *p_j2k,
                 return OPJ_FALSE;
         }
 
-        if (l_cp->m_specific_param.m_enc.m_cinema) {
+        if (OPJ_IS_CINEMA(l_cp->rsiz)) {
                 p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer =
                                 (OPJ_BYTE *) opj_malloc(5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts);
                 if (! p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) {
@@ -4702,7 +4765,7 @@ OPJ_BOOL opj_j2k_update_rates(  opj_j2k_t *p_j2k,
 }
 
 #if 0
-OPJ_BOOL opj_j2k_read_eoc (     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_eoc (     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager )
 {
@@ -4752,7 +4815,7 @@ OPJ_BOOL opj_j2k_read_eoc (     opj_j2k_t *p_j2k,
 }
 #endif
 
-OPJ_BOOL opj_j2k_get_end_header(opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_get_end_header(opj_j2k_t *p_j2k,
                                                         struct opj_stream_private *p_stream,
                                                         struct opj_event_mgr * p_manager )
 {
@@ -4766,7 +4829,7 @@ OPJ_BOOL opj_j2k_get_end_header(opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_mct_data_group(  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_mct_data_group(  opj_j2k_t *p_j2k,
                                                                         struct opj_stream_private *p_stream,
                                                                         struct opj_event_mgr * p_manager )
 {
@@ -4815,7 +4878,7 @@ OPJ_BOOL opj_j2k_write_mct_data_group(  opj_j2k_t *p_j2k,
 }
 
 #if 0
-OPJ_BOOL opj_j2k_write_all_coc(opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_all_coc(opj_j2k_t *p_j2k,
                                                                         struct opj_stream_private *p_stream,
                                                                         struct opj_event_mgr * p_manager )
 {
@@ -4838,7 +4901,7 @@ OPJ_BOOL opj_j2k_write_all_coc(opj_j2k_t *p_j2k,
 #endif
 
 #if 0
-OPJ_BOOL opj_j2k_write_all_qcc(opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_all_qcc(opj_j2k_t *p_j2k,
                                                                         struct opj_stream_private *p_stream,
                                                                         struct opj_event_mgr * p_manager )
 {
@@ -4861,7 +4924,7 @@ OPJ_BOOL opj_j2k_write_all_qcc(opj_j2k_t *p_j2k,
 #endif
 
 
-OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k,
                                                         struct opj_stream_private *p_stream,
                                                         struct opj_event_mgr * p_manager )
 {
@@ -4875,7 +4938,7 @@ OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k,
 
         l_tccp = p_j2k->m_cp.tcps->tccps;
 
-        for     (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno)  {
+        for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno)  {
                 if (l_tccp->roishift) {
 
                         if (! opj_j2k_write_rgn(p_j2k,0,compno,p_j2k->m_private_image->numcomps,p_stream,p_manager)) {
@@ -4889,7 +4952,7 @@ OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_epc(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_epc(     opj_j2k_t *p_j2k,
                                                 struct opj_stream_private *p_stream,
                                                 struct opj_event_mgr * p_manager )
 {
@@ -4927,7 +4990,7 @@ OPJ_BOOL opj_j2k_write_epc(     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_read_unk (     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_unk (     opj_j2k_t *p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         OPJ_UINT32 *output_marker,
                                                         opj_event_mgr_t * p_manager
@@ -4944,7 +5007,7 @@ OPJ_BOOL opj_j2k_read_unk (     opj_j2k_t *p_j2k,
 
         opj_event_msg(p_manager, EVT_WARNING, "Unknown marker\n");
 
-        while(1) {
+               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,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) {
                         opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
@@ -4989,7 +5052,7 @@ OPJ_BOOL opj_j2k_read_unk (     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_mct_record(      opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_mct_record(      opj_j2k_t *p_j2k,
                                                                 opj_mct_data_t * p_mct_record,
                                                                 struct opj_stream_private *p_stream,
                                                                 struct opj_event_mgr * p_manager )
@@ -5128,6 +5191,7 @@ static OPJ_BOOL opj_j2k_read_mct (      opj_j2k_t *p_j2k,
                 }
 
                 l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records;
+                ++l_tcp->m_nb_mct_records;
         }
 
         if (l_mct_data->m_data) {
@@ -5156,12 +5220,11 @@ static OPJ_BOOL opj_j2k_read_mct (      opj_j2k_t *p_j2k,
         memcpy(l_mct_data->m_data,p_header_data,p_header_size);
 
         l_mct_data->m_data_size = p_header_size;
-        ++l_tcp->m_nb_mct_records;
 
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_mcc_record(      opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_mcc_record(      opj_j2k_t *p_j2k,
                                                                 struct opj_simple_mcc_decorrelation_data * p_mcc_record,
                                                                 struct opj_stream_private *p_stream,
                                                                 struct opj_event_mgr * p_manager )
@@ -5264,7 +5327,7 @@ OPJ_BOOL opj_j2k_write_mcc_record(      opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_read_mcc (     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_mcc (     opj_j2k_t *p_j2k,
                                                 OPJ_BYTE * p_header_data,
                                                 OPJ_UINT32 p_header_size,
                                                 opj_event_mgr_t * p_manager )
@@ -5479,7 +5542,7 @@ OPJ_BOOL opj_j2k_read_mcc (     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_mco(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_mco(     opj_j2k_t *p_j2k,
                                                 struct opj_stream_private *p_stream,
                                                 struct opj_event_mgr * p_manager
                                   )
@@ -5609,7 +5672,7 @@ static OPJ_BOOL opj_j2k_read_mco (      opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index)
+static OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index)
 {
         OPJ_UINT32 i;
         opj_simple_mcc_decorrelation_data_t * l_mcc_record;
@@ -5691,7 +5754,7 @@ OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_cbd( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_cbd( opj_j2k_t *p_j2k,
                                                 struct opj_stream_private *p_stream,
                                                 struct opj_event_mgr * p_manager )
 {
@@ -5823,12 +5886,11 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters)
 
 opj_j2k_t* opj_j2k_create_compress(void)
 {
-        opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t));
+        opj_j2k_t *l_j2k = (opj_j2k_t*) opj_calloc(1,sizeof(opj_j2k_t));
         if (!l_j2k) {
                 return NULL;
         }
 
-        memset(l_j2k,0,sizeof(opj_j2k_t));
 
         l_j2k->m_is_decoder = 0;
         l_j2k->m_cp.m_is_decoder = 0;
@@ -5858,7 +5920,7 @@ opj_j2k_t* opj_j2k_create_compress(void)
         return l_j2k;
 }
 
-int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){
+static int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){
     POC[0].tile  = 1;
     POC[0].resno0  = 0;
     POC[0].compno0 = 0;
@@ -5876,27 +5938,11 @@ int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){
     return 2;
 }
 
-void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager)
+static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager)
 {
     /* Configure cinema parameters */
-    OPJ_FLOAT32 max_rate = 0;
-    OPJ_FLOAT32 temp_rate = 0;
     int i;
 
-    /* profile (Rsiz) */
-    switch (parameters->cp_cinema){
-    case OPJ_CINEMA2K_24:
-    case OPJ_CINEMA2K_48:
-        parameters->cp_rsiz = OPJ_CINEMA2K;
-        break;
-    case OPJ_CINEMA4K_24:
-        parameters->cp_rsiz = OPJ_CINEMA4K;
-        break;
-    case OPJ_OFF:
-        assert(0);
-        break;
-    }
-
     /* No tiling */
     parameters->tile_size_on = OPJ_FALSE;
     parameters->cp_tdx=1;
@@ -5934,15 +5980,16 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
         opj_event_msg(p_manager, EVT_WARNING,
                 "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
                 "1 single quality layer"
-                "-> Number of layers forced to 1 (rather than %d)\n",
-                parameters->tcp_numlayers);
+                "-> Number of layers forced to 1 (rather than %d)\n"
+                "-> Rate of the last layer (%3.1f) will be used",
+                parameters->tcp_numlayers, parameters->tcp_rates[parameters->tcp_numlayers-1]);
+        parameters->tcp_rates[0] = parameters->tcp_rates[parameters->tcp_numlayers-1];
         parameters->tcp_numlayers = 1;
     }
 
     /* Resolution levels */
-    switch (parameters->cp_cinema){
-    case OPJ_CINEMA2K_24:
-    case OPJ_CINEMA2K_48:
+    switch (parameters->rsiz){
+    case OPJ_PROFILE_CINEMA_2K:
         if(parameters->numresolution > 6){
             opj_event_msg(p_manager, EVT_WARNING,
                     "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
@@ -5952,7 +5999,7 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
             parameters->numresolution = 6;
         }
         break;
-    case OPJ_CINEMA4K_24:
+    case OPJ_PROFILE_CINEMA_4K:
         if(parameters->numresolution < 2){
             opj_event_msg(p_manager, EVT_WARNING,
                     "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
@@ -5985,7 +6032,7 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
     parameters->prog_order = OPJ_CPRL;
 
     /* Progression order changes for 4K, disallowed for 2K */
-    if (parameters->cp_cinema == OPJ_CINEMA4K_24) {
+    if (parameters->rsiz == OPJ_PROFILE_CINEMA_4K) {
         parameters->numpocs = (OPJ_UINT32)opj_j2k_initialise_4K_poc(parameters->POC,parameters->numresolution);
     } else {
         parameters->numpocs = 0;
@@ -5993,62 +6040,42 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i
 
     /* Limited bit-rate */
     parameters->cp_disto_alloc = 1;
-    switch (parameters->cp_cinema){
-    case OPJ_CINEMA2K_24:
-    case OPJ_CINEMA4K_24:
-        max_rate = (OPJ_FLOAT32) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/
-                (OPJ_FLOAT32)(CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy);
-        if (parameters->tcp_rates[0] == 0){
-            parameters->tcp_rates[0] = max_rate;
-        }else{
-            temp_rate =(OPJ_FLOAT32)(image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/
-                    (parameters->tcp_rates[0] * 8 * (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy);
-            if (temp_rate > CINEMA_24_CS ){
-                opj_event_msg(p_manager, EVT_WARNING,
-                        "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
-                        "Maximum 1302083 compressed bytes @ 24fps\n"
-                        "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n",
-                        parameters->tcp_rates[0], max_rate);
-                parameters->tcp_rates[0]= max_rate;
-            }else{
-                opj_event_msg(p_manager, EVT_WARNING,
-                        "JPEG 2000 Profile-3 and 4 (2k/4k dc profile):\n"
-                        "INFO : Specified rate (%3.1f) is below the 2k/4k limit @ 24fps.\n",
-                        parameters->tcp_rates[0]);
-            }
-        }
-        parameters->max_comp_size = COMP_24_CS;
-        break;
-    case OPJ_CINEMA2K_48:
-        max_rate = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
-                (float)(CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy);
-        if (parameters->tcp_rates[0] == 0){
-            parameters->tcp_rates[0] = max_rate;
-        }else{
-            temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
-                    (parameters->tcp_rates[0] * 8 * (float)image->comps[0].dx * (float)image->comps[0].dy);
-            if (temp_rate > CINEMA_48_CS ){
-                opj_event_msg(p_manager, EVT_WARNING,
-                        "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
-                        "Maximum 651041 compressed bytes @ 48fps\n"
-                        "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n",
-                        parameters->tcp_rates[0], max_rate);
-                parameters->tcp_rates[0]= max_rate;
-            }else{
-                opj_event_msg(p_manager, EVT_WARNING,
-                        "JPEG 2000 Profile-3 (2k dc profile):\n"
-                        "INFO : Specified rate (%3.1f) is below the 2k limit @ 48 fps.\n",
-                        parameters->tcp_rates[0]);
-            }
-        }
-        parameters->max_comp_size = COMP_48_CS;
-        break;
-    default:
-        break;
+    if (parameters->max_cs_size <= 0) {
+        /* No rate has been introduced, 24 fps is assumed */
+        parameters->max_cs_size = OPJ_CINEMA_24_CS;
+        opj_event_msg(p_manager, EVT_WARNING,
+                      "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                      "Maximum 1302083 compressed bytes @ 24fps\n"
+                      "As no rate has been given, this limit will be used.\n");
+    } else if (parameters->max_cs_size > OPJ_CINEMA_24_CS) {
+        opj_event_msg(p_manager, EVT_WARNING,
+                      "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                      "Maximum 1302083 compressed bytes @ 24fps\n"
+                      "-> Specified rate exceeds this limit. Rate will be forced to 1302083 bytes.\n");
+        parameters->max_cs_size = OPJ_CINEMA_24_CS;
+    }
+
+    if (parameters->max_comp_size <= 0) {
+        /* No rate has been introduced, 24 fps is assumed */
+        parameters->max_comp_size = OPJ_CINEMA_24_COMP;
+        opj_event_msg(p_manager, EVT_WARNING,
+                      "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                      "Maximum 1041666 compressed bytes @ 24fps\n"
+                      "As no rate has been given, this limit will be used.\n");
+    } else if (parameters->max_comp_size > OPJ_CINEMA_24_COMP) {
+        opj_event_msg(p_manager, EVT_WARNING,
+                      "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                      "Maximum 1041666 compressed bytes @ 24fps\n"
+                      "-> Specified rate exceeds this limit. Rate will be forced to 1041666 bytes.\n");
+        parameters->max_comp_size = OPJ_CINEMA_24_COMP;
     }
+
+    parameters->tcp_rates[0] = (OPJ_FLOAT32) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/
+            (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx * image->comps[0].dy);
+
 }
 
-OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager)
+static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager)
 {
     OPJ_UINT32 i;
 
@@ -6080,9 +6107,8 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_
     }
 
     /* Image size */
-    switch (cinema_mode){
-    case OPJ_CINEMA2K_24:
-    case OPJ_CINEMA2K_48:
+    switch (rsiz){
+    case OPJ_PROFILE_CINEMA_2K:
         if (((image->comps[0].w > 2048) | (image->comps[0].h > 1080))){
             opj_event_msg(p_manager, EVT_WARNING,
                     "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
@@ -6093,7 +6119,7 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_
             return OPJ_FALSE;
         }
         break;
-    case OPJ_CINEMA4K_24:
+    case OPJ_PROFILE_CINEMA_4K:
         if (((image->comps[0].w > 4096) | (image->comps[0].h > 2160))){
             opj_event_msg(p_manager, EVT_WARNING,
                     "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
@@ -6111,7 +6137,7 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_
     return OPJ_TRUE;
 }
 
-void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
+OPJ_BOOL opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                                                     opj_cparameters_t *parameters,
                                                     opj_image_t *image,
                                                     opj_event_mgr_t * p_manager)
@@ -6120,7 +6146,12 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
         opj_cp_t *cp = 00;
 
         if(!p_j2k || !parameters || ! image) {
-                return;
+                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 */
@@ -6130,20 +6161,130 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
         cp->tw = 1;
         cp->th = 1;
 
+        /* FIXME ADE: to be removed once deprecated cp_cinema and cp_rsiz have been removed */
+        if (parameters->rsiz == OPJ_PROFILE_NONE) { /* consider deprecated fields only if RSIZ has not been set */
+            OPJ_BOOL deprecated_used = OPJ_FALSE;
+            switch (parameters->cp_cinema){
+            case OPJ_CINEMA2K_24:
+                parameters->rsiz = OPJ_PROFILE_CINEMA_2K;
+                parameters->max_cs_size = OPJ_CINEMA_24_CS;
+                parameters->max_comp_size = OPJ_CINEMA_24_COMP;
+                deprecated_used = OPJ_TRUE;
+                break;
+            case OPJ_CINEMA2K_48:
+                parameters->rsiz = OPJ_PROFILE_CINEMA_2K;
+                parameters->max_cs_size = OPJ_CINEMA_48_CS;
+                parameters->max_comp_size = OPJ_CINEMA_48_COMP;
+                deprecated_used = OPJ_TRUE;
+                break;
+            case OPJ_CINEMA4K_24:
+                parameters->rsiz = OPJ_PROFILE_CINEMA_4K;
+                parameters->max_cs_size = OPJ_CINEMA_24_CS;
+                parameters->max_comp_size = OPJ_CINEMA_24_COMP;
+                deprecated_used = OPJ_TRUE;
+                break;
+            case OPJ_OFF:
+            default:
+                break;
+            }
+            switch (parameters->cp_rsiz){
+            case OPJ_CINEMA2K:
+                parameters->rsiz = OPJ_PROFILE_CINEMA_2K;
+                deprecated_used = OPJ_TRUE;
+                break;
+            case OPJ_CINEMA4K:
+                parameters->rsiz = OPJ_PROFILE_CINEMA_4K;
+                deprecated_used = OPJ_TRUE;
+                break;
+            case OPJ_MCT:
+                parameters->rsiz = OPJ_PROFILE_PART2 | OPJ_EXTENSION_MCT;
+                deprecated_used = OPJ_TRUE;
+            case OPJ_STD_RSIZ:
+            default:
+                break;
+            }
+            if (deprecated_used) {
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "Deprecated fields cp_cinema or cp_rsiz are used\n"
+                        "Please consider using only the rsiz field\n"
+                        "See openjpeg.h documentation for more details\n");
+            }
+        }
+
+        /* see if max_codestream_size does limit input rate */
+        if (parameters->max_cs_size <= 0) {
+            if (parameters->tcp_rates[parameters->tcp_numlayers-1] > 0) {
+                OPJ_FLOAT32 temp_size;
+                temp_size =(OPJ_FLOAT32)(image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/
+                        (parameters->tcp_rates[parameters->tcp_numlayers-1] * 8 * (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy);
+                parameters->max_cs_size = (int) floor(temp_size);
+            } else {
+                parameters->max_cs_size = 0;
+            }
+        } else {
+            OPJ_FLOAT32 temp_rate;
+            OPJ_BOOL cap = OPJ_FALSE;
+            temp_rate = (OPJ_FLOAT32) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/
+                    (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx * image->comps[0].dy);
+            for (i = 0; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
+                if (parameters->tcp_rates[i] < temp_rate) {
+                    parameters->tcp_rates[i] = temp_rate;
+                    cap = OPJ_TRUE;
+                }
+            }
+            if (cap) {
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "The desired maximum codestream size has limited\n"
+                        "at least one of the desired quality layers\n");
+            }
+        }
+
+        /* Manage profiles and applications and set RSIZ */
         /* set cinema parameters if required */
-        if (parameters->cp_cinema){
-            opj_j2k_set_cinema_parameters(parameters,image,p_manager);
-            if (!opj_j2k_is_cinema_compliant(image,parameters->cp_cinema,p_manager)) {
-                parameters->cp_rsiz = OPJ_STD_RSIZ;
+        if (OPJ_IS_CINEMA(parameters->rsiz)){
+            if ((parameters->rsiz == OPJ_PROFILE_CINEMA_S2K)
+                    || (parameters->rsiz == OPJ_PROFILE_CINEMA_S4K)){
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Scalable Digital Cinema profiles not yet supported\n");
+                parameters->rsiz = OPJ_PROFILE_NONE;
+            } else {
+                opj_j2k_set_cinema_parameters(parameters,image,p_manager);
+                if (!opj_j2k_is_cinema_compliant(image,parameters->rsiz,p_manager)) {
+                    parameters->rsiz = OPJ_PROFILE_NONE;
+                }
+            }
+        } else if (OPJ_IS_STORAGE(parameters->rsiz)) {
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Long Term Storage profile not yet supported\n");
+            parameters->rsiz = OPJ_PROFILE_NONE;
+        } else if (OPJ_IS_BROADCAST(parameters->rsiz)) {
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Broadcast profiles not yet supported\n");
+            parameters->rsiz = OPJ_PROFILE_NONE;
+        } else if (OPJ_IS_IMF(parameters->rsiz)) {
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 IMF profiles not yet supported\n");
+            parameters->rsiz = OPJ_PROFILE_NONE;
+        } else if (OPJ_IS_PART2(parameters->rsiz)) {
+            if (parameters->rsiz == ((OPJ_PROFILE_PART2) | (OPJ_EXTENSION_NONE))) {
+                opj_event_msg(p_manager, EVT_WARNING,
+                              "JPEG 2000 Part-2 profile defined\n"
+                              "but no Part-2 extension enabled.\n"
+                              "Profile set to NONE.\n");
+                parameters->rsiz = OPJ_PROFILE_NONE;
+            } else if (parameters->rsiz != ((OPJ_PROFILE_PART2) | (OPJ_EXTENSION_MCT))) {
+                opj_event_msg(p_manager, EVT_WARNING,
+                              "Unsupported Part-2 extension enabled\n"
+                              "Profile set to NONE.\n");
+                parameters->rsiz = OPJ_PROFILE_NONE;
             }
         }
 
         /*
         copy user encoding parameters
         */
-        cp->m_specific_param.m_enc.m_cinema = parameters->cp_cinema;
         cp->m_specific_param.m_enc.m_max_comp_size = (OPJ_UINT32)parameters->max_comp_size;
-        cp->rsiz   = parameters->cp_rsiz;
+        cp->rsiz = parameters->rsiz;
         cp->m_specific_param.m_enc.m_disto_alloc = (OPJ_UINT32)parameters->cp_disto_alloc & 1u;
         cp->m_specific_param.m_enc.m_fixed_alloc = (OPJ_UINT32)parameters->cp_fixed_alloc & 1u;
         cp->m_specific_param.m_enc.m_fixed_quality = (OPJ_UINT32)parameters->cp_fixed_quality & 1u;
@@ -6152,6 +6293,10 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
         if (parameters->cp_fixed_alloc && parameters->cp_matrice) {
                 size_t array_size = (size_t)parameters->tcp_numlayers * (size_t)parameters->numresolution * 3 * sizeof(OPJ_INT32);
                 cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size);
+                                                               if (!cp->m_specific_param.m_enc.m_matrice) {
+                                                                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate copy of user encoding parameters matrix \n");
+                                                                       return OPJ_FALSE;
+                                                               }
                 memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size);
         }
 
@@ -6165,11 +6310,36 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
 
         /* comment string */
         if(parameters->cp_comment) {
-                cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1);
-                if(cp->comment) {
-                        strcpy(cp->comment, parameters->cp_comment);
-                }
-        }
+                cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1U);
+                                                               if(!cp->comment) {
+                                                                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate copy of comment string\n");
+                                                                       return OPJ_FALSE;
+                                                               }
+                strcpy(cp->comment, parameters->cp_comment);
+        } else {
+                /* Create default comment for codestream */
+                const char comment[] = "Created by OpenJPEG version ";
+                const size_t clen = strlen(comment);
+                const char *version = opj_version();
+
+                /* UniPG>> */
+#ifdef USE_JPWL
+                cp->comment = (char*)opj_malloc(clen+strlen(version)+11);
+                                                               if(!cp->comment) {
+                                                                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate comment string\n");
+                                                                       return OPJ_FALSE;
+                                                               }
+                sprintf(cp->comment,"%s%s with JPWL", comment, version);
+#else
+                cp->comment = (char*)opj_malloc(clen+strlen(version)+1);
+                                                               if(!cp->comment) {
+                                                                       opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate comment string\n");
+                                                                       return OPJ_FALSE;
+                                                               }
+                sprintf(cp->comment,"%s%s", comment, version);
+#endif
+                /* <<UniPG */
+                               }
 
         /*
         calculate other encoding parameters
@@ -6247,6 +6417,10 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
         /* initialize the mutiple tiles */
         /* ---------------------------- */
         cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t));
+        if (!cp->tcps) {
+                opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate tile coding parameters\n");
+                return OPJ_FALSE;
+        }
         if (parameters->numpocs) {
                 /* initialisation of POC */
                 opj_j2k_check_poc_val(parameters->POC,parameters->numpocs, (OPJ_UINT32)parameters->numresolution, image->numcomps, (OPJ_UINT32)parameters->tcp_numlayers, p_manager);
@@ -6258,7 +6432,7 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                 tcp->numlayers = (OPJ_UINT32)parameters->tcp_numlayers;
 
                 for (j = 0; j < tcp->numlayers; j++) {
-                        if(cp->m_specific_param.m_enc.m_cinema){
+                        if(OPJ_IS_CINEMA(cp->rsiz)){
                                 if (cp->m_specific_param.m_enc.m_fixed_quality) {
                                         tcp->distoratio[j] = parameters->tcp_distoratio[j];
                                 }
@@ -6304,24 +6478,54 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                 }
 
                 tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t));
-
+                if (!tcp->tccps) {
+                        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate tile component coding parameters\n");
+                        return OPJ_FALSE;
+                }
                 if (parameters->mct_data) {
                       
                     OPJ_UINT32 lMctSize = image->numcomps * image->numcomps * (OPJ_UINT32)sizeof(OPJ_FLOAT32);
                     OPJ_FLOAT32 * lTmpBuf = (OPJ_FLOAT32*)opj_malloc(lMctSize);
                     OPJ_INT32 * l_dc_shift = (OPJ_INT32 *) ((OPJ_BYTE *) parameters->mct_data + lMctSize);
 
+                                                                               if (!lTmpBuf) {
+                            opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate temp buffer\n");
+                            return OPJ_FALSE;
+                    }
+
                     tcp->mct = 2;
                     tcp->m_mct_coding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize);
+                                                                               if (! tcp->m_mct_coding_matrix) {
+                            opj_free(lTmpBuf);
+                                                                                                               lTmpBuf = NULL;
+                            opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT coding matrix \n");
+                            return OPJ_FALSE;
+                    }
                     memcpy(tcp->m_mct_coding_matrix,parameters->mct_data,lMctSize);
                     memcpy(lTmpBuf,parameters->mct_data,lMctSize);
 
                     tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize);
-                    assert(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps));
+                                                                               if (! tcp->m_mct_decoding_matrix) {
+                                                                                                               opj_free(lTmpBuf);
+                                                                                                               lTmpBuf = NULL;
+                            opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT decoding matrix \n");
+                            return OPJ_FALSE;
+                    }
+                    if(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps) == OPJ_FALSE) {
+                            opj_free(lTmpBuf);
+                                                                                                               lTmpBuf = NULL;
+                            opj_event_msg(p_manager, EVT_ERROR, "Failed to inverse encoder MCT decoding matrix \n");
+                            return OPJ_FALSE;
+                                                                               }
 
                     tcp->mct_norms = (OPJ_FLOAT64*)
                                     opj_malloc(image->numcomps * sizeof(OPJ_FLOAT64));
-
+                                                                               if (! tcp->mct_norms) {
+                            opj_free(lTmpBuf);
+                                                                                                               lTmpBuf = NULL;
+                            opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT norms \n");
+                            return OPJ_FALSE;
+                    }
                     opj_calculate_norms(tcp->mct_norms,image->numcomps,tcp->m_mct_decoding_matrix);
                     opj_free(lTmpBuf);
 
@@ -6330,9 +6534,22 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                             tccp->m_dc_level_shift = l_dc_shift[i];
                     }
 
-                    opj_j2k_setup_mct_encoding(tcp,image);                        
+                    if (opj_j2k_setup_mct_encoding(tcp,image) == OPJ_FALSE) {
+                        /* free will be handled by opj_j2k_destroy */
+                                                                                               opj_event_msg(p_manager, EVT_ERROR, "Failed to setup j2k mct encoding\n");
+                        return OPJ_FALSE;
+                    }
                 }
                 else {
+                    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) ||
+                                (image->comps[0].dy != image->comps[2].dy)) {
+                            opj_event_msg(p_manager, EVT_WARNING, "Cannot perform MCT on components with different sizes. Disabling MCT.\n");
+                            tcp->mct = 0;
+                        }
+                    }
                         for (i = 0; i < image->numcomps; i++) {
                                 opj_tccp_t *tccp = &tcp->tccps[i];
                                 opj_image_comp_t * l_comp = &(image->comps[i]);
@@ -6419,6 +6636,7 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                 opj_free(parameters->mct_data);
                 parameters->mct_data = 00;
         }
+        return OPJ_TRUE;
 }
 
 static OPJ_BOOL opj_j2k_add_mhmarker(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len)
@@ -6522,7 +6740,11 @@ OPJ_BOOL opj_j2k_read_header(   opj_stream_private_t *p_stream,
         }
 
         /* customization of the validation */
-        opj_j2k_setup_decoding_validation(p_j2k);
+        if (! opj_j2k_setup_decoding_validation(p_j2k, p_manager)) {
+                opj_image_destroy(p_j2k->m_private_image);
+                p_j2k->m_private_image = NULL;
+                return OPJ_FALSE;
+        }
 
         /* validation of the parameters codec */
         if (! opj_j2k_exec(p_j2k, p_j2k->m_validation_list, p_stream,p_manager)) {
@@ -6532,7 +6754,11 @@ OPJ_BOOL opj_j2k_read_header(   opj_stream_private_t *p_stream,
         }
 
         /* customization of the encoding */
-        opj_j2k_setup_header_reading(p_j2k);
+        if (! opj_j2k_setup_header_reading(p_j2k, p_manager)) {
+                opj_image_destroy(p_j2k->m_private_image);
+                p_j2k->m_private_image = NULL;
+                return OPJ_FALSE;
+        }
 
         /* read header */
         if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) {
@@ -6557,30 +6783,42 @@ OPJ_BOOL opj_j2k_read_header(   opj_stream_private_t *p_stream,
         return OPJ_TRUE;
 }
 
-void opj_j2k_setup_header_reading (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_header_reading (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions*/
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_read_header_procedure);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_read_header_procedure, p_manager)) {
+                return OPJ_FALSE;
+        }
 
         /* DEVELOPER CORNER, add your custom procedures */
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_copy_default_tcp_and_create_tcd);
-
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_copy_default_tcp_and_create_tcd, p_manager))  {
+                return OPJ_FALSE;
+        }
+       
+        return OPJ_TRUE;
 }
 
-void opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions*/
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
-        opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_build_decoder);
-        opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_decoding_validation);
-        /* DEVELOPER CORNER, add your custom validation procedure */
+        if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list,(opj_procedure)opj_j2k_build_decoder, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list,(opj_procedure)opj_j2k_decoding_validation, p_manager)) {
+                return OPJ_FALSE;
+        }
 
+        /* DEVELOPER CORNER, add your custom validation procedure */
+        return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_mct_validation (       opj_j2k_t * p_j2k,
+static OPJ_BOOL opj_j2k_mct_validation (       opj_j2k_t * p_j2k,
                                                                 opj_stream_private_t *p_stream,
                                                                 opj_event_mgr_t * p_manager )
 {
@@ -6766,7 +7004,7 @@ OPJ_BOOL opj_j2k_setup_mct_encoding(opj_tcp_t * p_tcp, opj_image_t * p_image)
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_build_decoder (opj_j2k_t * p_j2k,
+static OPJ_BOOL opj_j2k_build_decoder (opj_j2k_t * p_j2k,
                                                             opj_stream_private_t *p_stream,
                                                             opj_event_mgr_t * p_manager )
 {
@@ -6778,7 +7016,7 @@ OPJ_BOOL opj_j2k_build_decoder (opj_j2k_t * p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_build_encoder (opj_j2k_t * p_j2k,
+static OPJ_BOOL opj_j2k_build_encoder (opj_j2k_t * p_j2k,
                                                         opj_stream_private_t *p_stream,
                                                         opj_event_mgr_t * p_manager )
 {
@@ -6790,7 +7028,7 @@ OPJ_BOOL opj_j2k_build_encoder (opj_j2k_t * p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_encoding_validation (  opj_j2k_t * p_j2k,
+static OPJ_BOOL opj_j2k_encoding_validation (  opj_j2k_t * p_j2k,
                                                                             opj_stream_private_t *p_stream,
                                                                             opj_event_mgr_t * p_manager )
 {
@@ -6811,12 +7049,20 @@ OPJ_BOOL opj_j2k_encoding_validation (  opj_j2k_t * p_j2k,
         /* 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.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)) {
+        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;
         }
@@ -6825,7 +7071,7 @@ OPJ_BOOL opj_j2k_encoding_validation (  opj_j2k_t * p_j2k,
         return l_is_valid;
 }
 
-OPJ_BOOL opj_j2k_decoding_validation (  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_decoding_validation (  opj_j2k_t *p_j2k,
                                         opj_stream_private_t *p_stream,
                                         opj_event_mgr_t * p_manager
                                         )
@@ -6855,13 +7101,16 @@ OPJ_BOOL opj_j2k_decoding_validation (  opj_j2k_t *p_j2k,
         return l_is_valid;
 }
 
-OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k,
                                                                             opj_stream_private_t *p_stream,
                                                                             opj_event_mgr_t * p_manager)
 {
         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);
@@ -6891,7 +7140,7 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k,
 
                 /* Check if the current marker ID is valid */
                 if (l_current_marker < 0xff00) {
-                        opj_event_msg(p_manager, EVT_ERROR, "We expected read a marker ID (0xff--) instead of %.8x\n", l_current_marker);
+                        opj_event_msg(p_manager, EVT_ERROR, "A marker ID was expected (0xff--) instead of %.8x\n", l_current_marker);
                         return OPJ_FALSE;
                 }
 
@@ -6911,6 +7160,19 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k,
                                 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");
@@ -6973,6 +7235,24 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k,
                 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;
+        }
+       
+        if (! opj_j2k_merge_ppm(&(p_j2k->m_cp), p_manager)) {
+            opj_event_msg(p_manager, EVT_ERROR, "Failed to merge PPM data\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 */
@@ -6984,7 +7264,7 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_exec ( opj_j2k_t * p_j2k,
+static OPJ_BOOL opj_j2k_exec ( opj_j2k_t * p_j2k,
                                         opj_procedure_list_t * p_procedure_list,
                                         opj_stream_private_t *p_stream,
                                         opj_event_mgr_t * p_manager )
@@ -7050,8 +7330,15 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd (       opj_j2k_t * p_j2
                 /*Copy default coding parameters into the current tile coding parameters*/
                 memcpy(l_tcp, l_default_tcp, sizeof(opj_tcp_t));
                 /* Initialize some values of the current tile coding parameters*/
+                l_tcp->cod = 0;
                 l_tcp->ppt = 0;
                 l_tcp->ppt_data = 00;
+                /* Remove memory not owned by this tile in case of early error return. */
+                l_tcp->m_mct_decoding_matrix = 00;
+                l_tcp->m_nb_max_mct_records = 0;
+                l_tcp->m_mct_records = 00;
+                l_tcp->m_nb_max_mcc_records = 0;
+                l_tcp->m_mcc_records = 00;
                 /* Reconnect the tile-compo coding parameters pointer to the current tile coding parameters*/
                 l_tcp->tccps = l_current_tccp;
 
@@ -7089,6 +7376,8 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd (       opj_j2k_t * p_j2
 
                         ++l_src_mct_rec;
                         ++l_dest_mct_rec;
+                        /* Update with each pass to free exactly what has been allocated on early return. */
+                        l_tcp->m_nb_max_mct_records += 1;
                 }
 
                 /* Get the mcc_record of the dflt_tile_cp and copy them into the current tile cp*/
@@ -7098,6 +7387,7 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd (       opj_j2k_t * p_j2
                         return OPJ_FALSE;
                 }
                 memcpy(l_tcp->m_mcc_records,l_default_tcp->m_mcc_records,l_mcc_records_size);
+                l_tcp->m_nb_max_mcc_records = l_default_tcp->m_nb_max_mcc_records;
 
                 /* Copy the mcc record data from dflt_tile_cp to the current tile*/
                 l_src_mcc_rec = l_default_tcp->m_mcc_records;
@@ -7142,7 +7432,7 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd (       opj_j2k_t * p_j2
         return OPJ_TRUE;
 }
 
-const opj_dec_memory_marker_handler_t * opj_j2k_get_marker_handler (OPJ_UINT32 p_id)
+static const opj_dec_memory_marker_handler_t * opj_j2k_get_marker_handler (OPJ_UINT32 p_id)
 {
         const opj_dec_memory_marker_handler_t *e;
         for (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) {
@@ -7255,66 +7545,78 @@ void j2k_destroy_cstr_index (opj_codestream_index_t *p_cstr_ind)
         }
 }
 
-void opj_j2k_tcp_destroy (opj_tcp_t *p_tcp)
+static void opj_j2k_tcp_destroy (opj_tcp_t *p_tcp)
 {
-        if (p_tcp == 00) {
-                return;
-        }
-
-        if (p_tcp->ppt_buffer != 00) {
-                opj_free(p_tcp->ppt_buffer);
-                p_tcp->ppt_buffer = 00;
-        }
-
-        if (p_tcp->tccps != 00) {
-                opj_free(p_tcp->tccps);
-                p_tcp->tccps = 00;
-        }
-
-        if (p_tcp->m_mct_coding_matrix != 00) {
-                opj_free(p_tcp->m_mct_coding_matrix);
-                p_tcp->m_mct_coding_matrix = 00;
-        }
-
-        if (p_tcp->m_mct_decoding_matrix != 00) {
-                opj_free(p_tcp->m_mct_decoding_matrix);
-                p_tcp->m_mct_decoding_matrix = 00;
-        }
-
-        if (p_tcp->m_mcc_records) {
-                opj_free(p_tcp->m_mcc_records);
-                p_tcp->m_mcc_records = 00;
-                p_tcp->m_nb_max_mcc_records = 0;
-                p_tcp->m_nb_mcc_records = 0;
-        }
-
-        if (p_tcp->m_mct_records) {
-                opj_mct_data_t * l_mct_data = p_tcp->m_mct_records;
-                OPJ_UINT32 i;
-
-                for (i=0;i<p_tcp->m_nb_mct_records;++i) {
-                        if (l_mct_data->m_data) {
-                                opj_free(l_mct_data->m_data);
-                                l_mct_data->m_data = 00;
-                        }
-
-                        ++l_mct_data;
-                }
-
-                opj_free(p_tcp->m_mct_records);
-                p_tcp->m_mct_records = 00;
-        }
+       if (p_tcp == 00) {
+               return;
+       }
+       
+       if (p_tcp->ppt_markers != 00) {
+               OPJ_UINT32 i;
+               for (i = 0U; i < p_tcp->ppt_markers_count; ++i) {
+                       if (p_tcp->ppt_markers[i].m_data != NULL) {
+                               opj_free(p_tcp->ppt_markers[i].m_data);
+                       }
+               }
+               p_tcp->ppt_markers_count = 0U;
+               opj_free(p_tcp->ppt_markers);
+               p_tcp->ppt_markers = NULL;
+       }
+       
+       if (p_tcp->ppt_buffer != 00) {
+               opj_free(p_tcp->ppt_buffer);
+               p_tcp->ppt_buffer = 00;
+       }
+       
+       if (p_tcp->tccps != 00) {
+               opj_free(p_tcp->tccps);
+               p_tcp->tccps = 00;
+       }
+       
+       if (p_tcp->m_mct_coding_matrix != 00) {
+               opj_free(p_tcp->m_mct_coding_matrix);
+               p_tcp->m_mct_coding_matrix = 00;
+       }
+       
+       if (p_tcp->m_mct_decoding_matrix != 00) {
+               opj_free(p_tcp->m_mct_decoding_matrix);
+               p_tcp->m_mct_decoding_matrix = 00;
+       }
+       
+       if (p_tcp->m_mcc_records) {
+               opj_free(p_tcp->m_mcc_records);
+               p_tcp->m_mcc_records = 00;
+               p_tcp->m_nb_max_mcc_records = 0;
+               p_tcp->m_nb_mcc_records = 0;
+       }
+       
+       if (p_tcp->m_mct_records) {
+               opj_mct_data_t * l_mct_data = p_tcp->m_mct_records;
+               OPJ_UINT32 i;
+               
+               for (i=0;i<p_tcp->m_nb_mct_records;++i) {
+                       if (l_mct_data->m_data) {
+                               opj_free(l_mct_data->m_data);
+                               l_mct_data->m_data = 00;
+                       }
+                       
+                       ++l_mct_data;
+               }
+               
+               opj_free(p_tcp->m_mct_records);
+               p_tcp->m_mct_records = 00;
+       }
 
-        if (p_tcp->mct_norms != 00) {
-                opj_free(p_tcp->mct_norms);
-                p_tcp->mct_norms = 00;
-        }
+       if (p_tcp->mct_norms != 00) {
+               opj_free(p_tcp->mct_norms);
+               p_tcp->mct_norms = 00;
+       }
 
-        opj_j2k_tcp_data_destroy(p_tcp);
+       opj_j2k_tcp_data_destroy(p_tcp);
 
 }
 
-void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp)
+static void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp)
 {
         if (p_tcp->m_data) {
                 opj_free(p_tcp->m_data);
@@ -7323,39 +7625,148 @@ void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp)
         }
 }
 
-void opj_j2k_cp_destroy (opj_cp_t *p_cp)
+static void opj_j2k_cp_destroy (opj_cp_t *p_cp)
 {
-        OPJ_UINT32 l_nb_tiles;
-        opj_tcp_t * l_current_tile = 00;
-        OPJ_UINT32 i;
+       OPJ_UINT32 l_nb_tiles;
+       opj_tcp_t * l_current_tile = 00;
 
-        if (p_cp == 00)
-        {
-                return;
-        }
-        if (p_cp->tcps != 00)
-        {
-                l_current_tile = p_cp->tcps;
-                l_nb_tiles = p_cp->th * p_cp->tw;
-
-                for (i = 0; i < l_nb_tiles; ++i)
-                {
-                        opj_j2k_tcp_destroy(l_current_tile);
-                        ++l_current_tile;
-                }
-                opj_free(p_cp->tcps);
-                p_cp->tcps = 00;
-        }
-        opj_free(p_cp->ppm_buffer);
-        p_cp->ppm_buffer = 00;
-        p_cp->ppm_data = NULL; /* ppm_data belongs to the allocated buffer pointed by ppm_buffer */
-        opj_free(p_cp->comment);
-        p_cp->comment = 00;
-        if (! p_cp->m_is_decoder)
-        {
-                opj_free(p_cp->m_specific_param.m_enc.m_matrice);
-                p_cp->m_specific_param.m_enc.m_matrice = 00;
-        }
+       if (p_cp == 00)
+       {
+               return;
+       }
+       if (p_cp->tcps != 00)
+       {
+               OPJ_UINT32 i;
+               l_current_tile = p_cp->tcps;
+               l_nb_tiles = p_cp->th * p_cp->tw;
+               
+               for (i = 0U; i < l_nb_tiles; ++i)
+               {
+                       opj_j2k_tcp_destroy(l_current_tile);
+                       ++l_current_tile;
+               }
+               opj_free(p_cp->tcps);
+               p_cp->tcps = 00;
+       }
+       if (p_cp->ppm_markers != 00) {
+               OPJ_UINT32 i;
+               for (i = 0U; i < p_cp->ppm_markers_count; ++i) {
+                       if (p_cp->ppm_markers[i].m_data != NULL) {
+                               opj_free(p_cp->ppm_markers[i].m_data);
+                       }
+               }
+               p_cp->ppm_markers_count = 0U;
+               opj_free(p_cp->ppm_markers);
+               p_cp->ppm_markers = NULL;
+       }
+       opj_free(p_cp->ppm_buffer);
+       p_cp->ppm_buffer = 00;
+       p_cp->ppm_data = NULL; /* ppm_data belongs to the allocated buffer pointed by ppm_buffer */
+       opj_free(p_cp->comment);
+       p_cp->comment = 00;
+       if (! p_cp->m_is_decoder)
+       {
+               opj_free(p_cp->m_specific_param.m_enc.m_matrice);
+               p_cp->m_specific_param.m_enc.m_matrice = 00;
+       }
+}
+
+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,
@@ -7372,7 +7783,6 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
         OPJ_UINT32 l_marker_size;
         const opj_dec_memory_marker_handler_t * l_marker_handler = 00;
         opj_tcp_t * l_tcp = NULL;
-        OPJ_UINT32 l_nb_tiles;
 
         /* preconditions */
         assert(p_stream != 00);
@@ -7409,6 +7819,12 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
                         /* Read 2 bytes from the buffer as the marker size */
                         opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2);
 
+                        /* Check marker size (does not include marker ID but includes marker size) */
+                        if (l_marker_size < 2) {
+                                opj_event_msg(p_manager, EVT_ERROR, "Inconsistent marker size\n");
+                                return OPJ_FALSE;
+                        }
+
                         /* cf. https://code.google.com/p/openjpeg/issues/detail?id=226 */
                         if (l_current_marker == 0x8080 && opj_stream_get_number_byte_left(p_stream) == 0) {
                                 p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
@@ -7433,7 +7849,14 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
 
                         /* Check if the marker size is compatible with the header data size */
                         if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) {
-                                OPJ_BYTE *new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size);
+                                OPJ_BYTE *new_header_data = NULL;
+                                /* If we are here, this means we consider this marker as known & we will read it */
+                                /* Check enough bytes left in stream before allocation */
+                                if ((OPJ_OFF_T)l_marker_size >  opj_stream_get_number_byte_left(p_stream)) {
+                                        opj_event_msg(p_manager, EVT_ERROR, "Marker size inconsistent with stream length\n");
+                                        return OPJ_FALSE;
+                                }
+                                new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size);
                                 if (! new_header_data) {
                                         opj_free(p_j2k->m_specific_param.m_decoder.m_header_data);
                                         p_j2k->m_specific_param.m_decoder.m_header_data = NULL;
@@ -7509,7 +7932,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) {
@@ -7548,8 +7994,8 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
 
         /* FIXME DOC ???*/
         if ( ! p_j2k->m_specific_param.m_decoder.m_can_decode) {
+                OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
                 l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number;
-                l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
 
                 while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00) ) {
                         ++p_j2k->m_current_tile_number;
@@ -7562,14 +8008,18 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
                 }
         }
 
+        if (! opj_j2k_merge_ppt(p_j2k->m_cp.tcps + p_j2k->m_current_tile_number, p_manager)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Failed to merge PPT data\n");
+                return OPJ_FALSE;
+        }
         /*FIXME ???*/
-        if (! opj_tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) {
+        if (! opj_tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number, p_manager)) {
                 opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n");
                 return OPJ_FALSE;
         }
 
         opj_event_msg(p_manager, EVT_INFO, "Header of tile %d / %d has been read.\n",
-                        p_j2k->m_current_tile_number, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1);
+                        p_j2k->m_current_tile_number+1, (p_j2k->m_cp.th * p_j2k->m_cp.tw));
 
         *p_tile_index = p_j2k->m_current_tile_number;
         *p_go_on = OPJ_TRUE;
@@ -7616,9 +8066,10 @@ OPJ_BOOL opj_j2k_decode_tile (  opj_j2k_t * p_j2k,
                                                                 l_tcp->m_data,
                                                                 l_tcp->m_data_size,
                                                                 p_tile_index,
-                                                                p_j2k->cstr_index) ) {
+                                                                p_j2k->cstr_index, p_manager) ) {
                 opj_j2k_tcp_destroy(l_tcp);
                 p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/*FIXME J2K_DEC_STATE_ERR;*/
+                opj_event_msg(p_manager, EVT_ERROR, "Failed to decode.\n");
                 return OPJ_FALSE;
         }
 
@@ -7653,13 +8104,13 @@ OPJ_BOOL opj_j2k_decode_tile (  opj_j2k_t * p_j2k,
                         p_j2k->m_specific_param.m_decoder.m_state =  0x0100;/*FIXME J2K_DEC_STATE_EOC;*/
                 }
                 else if (l_current_marker != J2K_MS_SOT)
-                {
-                        opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n");
-                        
+                {       
                         if(opj_stream_get_number_byte_left(p_stream) == 0) {
                             p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
+                            opj_event_msg(p_manager, EVT_WARNING, "Stream does not end with EOC\n");
                             return OPJ_TRUE;
                         }
+                        opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n");
                         return OPJ_FALSE;
                 }
         }
@@ -7667,16 +8118,16 @@ OPJ_BOOL opj_j2k_decode_tile (  opj_j2k_t * p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image)
+static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image)
 {
         OPJ_UINT32 i,j,k = 0;
         OPJ_UINT32 l_width_src,l_height_src;
         OPJ_UINT32 l_width_dest,l_height_dest;
         OPJ_INT32 l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src;
-        OPJ_INT32 l_start_offset_src, l_line_offset_src, l_end_offset_src ;
+        OPJ_SIZE_T l_start_offset_src, l_line_offset_src, l_end_offset_src ;
         OPJ_UINT32 l_start_x_dest , l_start_y_dest;
         OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_dest;
-        OPJ_INT32 l_start_offset_dest, l_line_offset_dest;
+        OPJ_SIZE_T l_start_offset_dest, l_line_offset_dest;
 
         opj_image_comp_t * l_img_comp_src = 00;
         opj_image_comp_t * l_img_comp_dest = 00;
@@ -7698,7 +8149,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im
                 /* Allocate output component buffer if necessary */
                 if (!l_img_comp_dest->data) {
 
-                        l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_img_comp_dest->w * l_img_comp_dest->h, sizeof(OPJ_INT32));
+                        l_img_comp_dest->data = (OPJ_INT32*) opj_calloc((OPJ_SIZE_T)l_img_comp_dest->w * (OPJ_SIZE_T)l_img_comp_dest->h, sizeof(OPJ_INT32));
                         if (! l_img_comp_dest->data) {
                                 return OPJ_FALSE;
                         }
@@ -7732,9 +8183,9 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im
                 l_height_src = (OPJ_UINT32)(l_res->y1 - l_res->y0);
 
                 /* Border of the current output component*/
-                l_x0_dest = (OPJ_UINT32)opj_int_ceildivpow2((OPJ_INT32)l_img_comp_dest->x0, (OPJ_INT32)l_img_comp_dest->factor);
-                l_y0_dest = (OPJ_UINT32)opj_int_ceildivpow2((OPJ_INT32)l_img_comp_dest->y0, (OPJ_INT32)l_img_comp_dest->factor);
-                l_x1_dest = l_x0_dest + l_img_comp_dest->w;
+                l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor);
+                l_y0_dest = opj_uint_ceildivpow2(l_img_comp_dest->y0, l_img_comp_dest->factor);
+                l_x1_dest = l_x0_dest + l_img_comp_dest->w; /* can't overflow given that image->x1 is uint32 */
                 l_y1_dest = l_y0_dest + l_img_comp_dest->h;
 
                 /*if (i == 0) {
@@ -7765,7 +8216,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im
                         }
                 }
                 else {
-                        l_start_x_dest = 0 ;
+                        l_start_x_dest = 0U;
                         l_offset_x0_src = (OPJ_INT32)l_x0_dest - l_res->x0;
 
                         if ( l_x1_dest >= (OPJ_UINT32)l_res->x1 ) {
@@ -7792,7 +8243,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im
                         }
                 }
                 else {
-                        l_start_y_dest = 0 ;
+                        l_start_y_dest = 0U;
                         l_offset_y0_src = (OPJ_INT32)l_y0_dest - l_res->y0;
 
                         if ( l_y1_dest >= (OPJ_UINT32)l_res->y1 ) {
@@ -7815,13 +8266,13 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im
                 /*-----*/
 
                 /* Compute the input buffer offset */
-                l_start_offset_src = l_offset_x0_src + l_offset_y0_src * (OPJ_INT32)l_width_src;
-                l_line_offset_src = l_offset_x1_src + l_offset_x0_src;
-                l_end_offset_src = l_offset_y1_src * (OPJ_INT32)l_width_src - l_offset_x0_src;
+                l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src * (OPJ_SIZE_T)l_width_src;
+                l_line_offset_src  = (OPJ_SIZE_T)l_offset_x1_src + (OPJ_SIZE_T)l_offset_x0_src;
+                l_end_offset_src   = (OPJ_SIZE_T)l_offset_y1_src * (OPJ_SIZE_T)l_width_src - (OPJ_SIZE_T)l_offset_x0_src;
 
                 /* Compute the output buffer offset */
-                l_start_offset_dest = (OPJ_INT32)(l_start_x_dest + l_start_y_dest * l_img_comp_dest->w);
-                l_line_offset_dest = (OPJ_INT32)(l_img_comp_dest->w - l_width_dest);
+                l_start_offset_dest = (OPJ_SIZE_T)l_start_x_dest + (OPJ_SIZE_T)l_start_y_dest * (OPJ_SIZE_T)l_img_comp_dest->w;
+                l_line_offset_dest  = (OPJ_SIZE_T)l_img_comp_dest->w - (OPJ_SIZE_T)l_width_dest;
 
                 /* Move the output buffer to the first place where we will write*/
                 l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest;
@@ -8087,23 +8538,25 @@ OPJ_BOOL opj_j2k_set_decode_area(       opj_j2k_t *p_j2k,
 
 opj_j2k_t* opj_j2k_create_decompress(void)
 {
-        opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t));
+        opj_j2k_t *l_j2k = (opj_j2k_t*) opj_calloc(1,sizeof(opj_j2k_t));
         if (!l_j2k) {
                 return 00;
         }
-        memset(l_j2k,0,sizeof(opj_j2k_t));
 
         l_j2k->m_is_decoder = 1;
         l_j2k->m_cp.m_is_decoder = 1;
 
-        l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_malloc(sizeof(opj_tcp_t));
+#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);
                 return 00;
         }
-        memset(l_j2k->m_specific_param.m_decoder.m_default_tcp,0,sizeof(opj_tcp_t));
 
-        l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_malloc(OPJ_J2K_DEFAULT_HEADER_SIZE);
+        l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_calloc(1,OPJ_J2K_DEFAULT_HEADER_SIZE);
         if (! l_j2k->m_specific_param.m_decoder.m_header_data) {
                 opj_j2k_destroy(l_j2k);
                 return 00;
@@ -8117,16 +8570,11 @@ opj_j2k_t* opj_j2k_create_decompress(void)
 
         /* codestream index creation */
         l_j2k->cstr_index = opj_j2k_create_cstr_index();
-
-                        /*(opj_codestream_index_t*) opj_malloc(sizeof(opj_codestream_index_t));
         if (!l_j2k->cstr_index){
                 opj_j2k_destroy(l_j2k);
-                return NULL;
+                return 00;
         }
 
-        l_j2k->cstr_index->marker = (opj_marker_info_t*) opj_malloc(100 * sizeof(opj_marker_info_t));
-*/
-
         /* validation list creation */
         l_j2k->m_validation_list = opj_procedure_list_create();
         if (! l_j2k->m_validation_list) {
@@ -8144,7 +8592,7 @@ opj_j2k_t* opj_j2k_create_decompress(void)
         return l_j2k;
 }
 
-opj_codestream_index_t* opj_j2k_create_cstr_index(void)
+static opj_codestream_index_t* opj_j2k_create_cstr_index(void)
 {
         opj_codestream_index_t* cstr_index = (opj_codestream_index_t*)
                         opj_calloc(1,sizeof(opj_codestream_index_t));
@@ -8163,7 +8611,7 @@ opj_codestream_index_t* opj_j2k_create_cstr_index(void)
         return cstr_index;
 }
 
-OPJ_UINT32 opj_j2k_get_SPCod_SPCoc_size (       opj_j2k_t *p_j2k,
+static OPJ_UINT32 opj_j2k_get_SPCod_SPCoc_size (       opj_j2k_t *p_j2k,
                                                                                 OPJ_UINT32 p_tile_no,
                                                                                 OPJ_UINT32 p_comp_no )
 {
@@ -8190,7 +8638,7 @@ OPJ_UINT32 opj_j2k_get_SPCod_SPCoc_size (       opj_j2k_t *p_j2k,
         }
 }
 
-OPJ_BOOL opj_j2k_write_SPCod_SPCoc(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_SPCod_SPCoc(     opj_j2k_t *p_j2k,
                                                                     OPJ_UINT32 p_tile_no,
                                                                     OPJ_UINT32 p_comp_no,
                                                                     OPJ_BYTE * p_data,
@@ -8256,7 +8704,7 @@ OPJ_BOOL opj_j2k_write_SPCod_SPCoc(     opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_read_SPCod_SPCoc(  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(  opj_j2k_t *p_j2k,
                                                                 OPJ_UINT32 compno,
                                                                 OPJ_BYTE * p_header_data,
                                                                 OPJ_UINT32 * p_header_size,
@@ -8316,6 +8764,12 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc(  opj_j2k_t *p_j2k,
         ++l_current_ptr;
         l_tccp->cblkh += 2;
 
+        if ((l_tccp->cblkw > 10) || (l_tccp->cblkh > 10) || ((l_tccp->cblkw + l_tccp->cblkh) > 12)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element, Invalid cblkw/cblkh combination\n");
+                return OPJ_FALSE;
+        }
+       
+
         opj_read_bytes(l_current_ptr,&l_tccp->cblksty ,1);              /* SPcoc (G) */
         ++l_current_ptr;
 
@@ -8334,6 +8788,11 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc(  opj_j2k_t *p_j2k,
                 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;
                 }
@@ -8368,7 +8827,7 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc(  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-void opj_j2k_copy_tile_component_parameters( opj_j2k_t *p_j2k )
+static void opj_j2k_copy_tile_component_parameters( opj_j2k_t *p_j2k )
 {
         /* loop */
         OPJ_UINT32 i;
@@ -8401,7 +8860,7 @@ void opj_j2k_copy_tile_component_parameters( opj_j2k_t *p_j2k )
         }
 }
 
-OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k,
+static OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k,
                                                                         OPJ_UINT32 p_tile_no,
                                                                         OPJ_UINT32 p_comp_no )
 {
@@ -8432,7 +8891,7 @@ OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k,
         }
 }
 
-OPJ_BOOL opj_j2k_write_SQcd_SQcc(       opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_SQcd_SQcc(       opj_j2k_t *p_j2k,
                                                                 OPJ_UINT32 p_tile_no,
                                                                 OPJ_UINT32 p_comp_no,
                                                                 OPJ_BYTE * p_data,
@@ -8505,7 +8964,7 @@ OPJ_BOOL opj_j2k_write_SQcd_SQcc(       opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_read_SQcd_SQcc(opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_read_SQcd_SQcc(opj_j2k_t *p_j2k,
                                                             OPJ_UINT32 p_comp_no,
                                                             OPJ_BYTE* p_header_data,
                                                             OPJ_UINT32 * p_header_size,
@@ -8622,7 +9081,7 @@ OPJ_BOOL opj_j2k_read_SQcd_SQcc(opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-void opj_j2k_copy_tile_quantization_parameters( opj_j2k_t *p_j2k )
+static void opj_j2k_copy_tile_quantization_parameters( opj_j2k_t *p_j2k )
 {
         OPJ_UINT32 i;
         opj_cp_t *l_cp = NULL;
@@ -8651,6 +9110,58 @@ void opj_j2k_copy_tile_quantization_parameters( opj_j2k_t *p_j2k )
         }
 }
 
+static void opj_j2k_dump_tile_info( opj_tcp_t * l_default_tile,OPJ_INT32 numcomps,FILE* out_stream)
+{
+        if (l_default_tile)
+        {
+                OPJ_INT32 compno;
+
+                fprintf(out_stream, "\t default tile {\n");
+                fprintf(out_stream, "\t\t csty=%#x\n", l_default_tile->csty);
+                fprintf(out_stream, "\t\t prg=%#x\n", l_default_tile->prg);
+                fprintf(out_stream, "\t\t numlayers=%d\n", l_default_tile->numlayers);
+                fprintf(out_stream, "\t\t mct=%x\n", l_default_tile->mct);
+
+                for (compno = 0; compno < numcomps; compno++) {
+                        opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]);
+                        OPJ_UINT32 resno;
+      OPJ_INT32 bandno, numbands;
+
+                        /* coding style*/
+                        fprintf(out_stream, "\t\t comp %d {\n", compno);
+                        fprintf(out_stream, "\t\t\t csty=%#x\n", l_tccp->csty);
+                        fprintf(out_stream, "\t\t\t numresolutions=%d\n", l_tccp->numresolutions);
+                        fprintf(out_stream, "\t\t\t cblkw=2^%d\n", l_tccp->cblkw);
+                        fprintf(out_stream, "\t\t\t cblkh=2^%d\n", l_tccp->cblkh);
+                        fprintf(out_stream, "\t\t\t cblksty=%#x\n", l_tccp->cblksty);
+                        fprintf(out_stream, "\t\t\t qmfbid=%d\n", l_tccp->qmfbid);
+
+                        fprintf(out_stream, "\t\t\t preccintsize (w,h)=");
+                        for (resno = 0; resno < l_tccp->numresolutions; resno++) {
+                                fprintf(out_stream, "(%d,%d) ", l_tccp->prcw[resno], l_tccp->prch[resno]);
+                        }
+                        fprintf(out_stream, "\n");
+
+                        /* quantization style*/
+                        fprintf(out_stream, "\t\t\t qntsty=%d\n", l_tccp->qntsty);
+                        fprintf(out_stream, "\t\t\t numgbits=%d\n", l_tccp->numgbits);
+                        fprintf(out_stream, "\t\t\t stepsizes (m,e)=");
+                        numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (OPJ_INT32)l_tccp->numresolutions * 3 - 2;
+                        for (bandno = 0; bandno < numbands; bandno++) {
+                                fprintf(out_stream, "(%d,%d) ", l_tccp->stepsizes[bandno].mant,
+                                        l_tccp->stepsizes[bandno].expn);
+                        }
+                        fprintf(out_stream, "\n");
+
+                        /* RGN value*/
+                        fprintf(out_stream, "\t\t\t roishift=%d\n", l_tccp->roishift);
+
+                        fprintf(out_stream, "\t\t }\n");
+                } /*end of component of default tile*/
+                fprintf(out_stream, "\t }\n"); /*end of default tile*/
+            }
+}
+
 void j2k_dump (opj_j2k_t* p_j2k, OPJ_INT32 flag, FILE* out_stream)
 {
         /* Check if the flag is compatible with j2k file*/
@@ -8669,6 +9180,16 @@ void j2k_dump (opj_j2k_t* p_j2k, OPJ_INT32 flag, FILE* out_stream)
         if (flag & OPJ_J2K_MH_INFO){
                 opj_j2k_dump_MH_info(p_j2k, out_stream);
         }
+        /* Dump all tile/codestream info */
+        if (flag & OPJ_J2K_TCH_INFO){
+          OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
+          OPJ_UINT32 i;
+          opj_tcp_t * l_tcp = p_j2k->m_cp.tcps;
+          for (i=0;i<l_nb_tiles;++i) {
+            opj_j2k_dump_tile_info( l_tcp,(OPJ_INT32)p_j2k->m_private_image->numcomps, out_stream);
+            ++l_tcp;
+          }
+        }
 
         /* Dump the codestream info of the current tile */
         if (flag & OPJ_J2K_TH_INFO){
@@ -8687,7 +9208,7 @@ void j2k_dump (opj_j2k_t* p_j2k, OPJ_INT32 flag, FILE* out_stream)
 
 }
 
-void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream)
+static void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream)
 {
         opj_codestream_index_t* cstr_index = p_j2k->cstr_index;
         OPJ_UINT32 it_marker, it_tile, it_tile_part;
@@ -8755,70 +9276,17 @@ void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream)
 
 }
 
-void opj_j2k_dump_MH_info(opj_j2k_t* p_j2k, FILE* out_stream)
+
+static void opj_j2k_dump_MH_info(opj_j2k_t* p_j2k, FILE* out_stream)
 {
-        opj_tcp_t * l_default_tile=NULL;
 
         fprintf(out_stream, "Codestream info from main header: {\n");
 
         fprintf(out_stream, "\t tx0=%d, ty0=%d\n", p_j2k->m_cp.tx0, p_j2k->m_cp.ty0);
         fprintf(out_stream, "\t tdx=%d, tdy=%d\n", p_j2k->m_cp.tdx, p_j2k->m_cp.tdy);
         fprintf(out_stream, "\t tw=%d, th=%d\n", p_j2k->m_cp.tw, p_j2k->m_cp.th);
-
-        l_default_tile = p_j2k->m_specific_param.m_decoder.m_default_tcp;
-        if (l_default_tile)
-        {
-                OPJ_INT32 compno;
-                OPJ_INT32 numcomps = (OPJ_INT32)p_j2k->m_private_image->numcomps;
-
-                fprintf(out_stream, "\t default tile {\n");
-                fprintf(out_stream, "\t\t csty=%#x\n", l_default_tile->csty);
-                fprintf(out_stream, "\t\t prg=%#x\n", l_default_tile->prg);
-                fprintf(out_stream, "\t\t numlayers=%d\n", l_default_tile->numlayers);
-                fprintf(out_stream, "\t\t mct=%x\n", l_default_tile->mct);
-
-                for (compno = 0; compno < numcomps; compno++) {
-                        opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]);
-                        OPJ_UINT32 resno;
-      OPJ_INT32 bandno, numbands;
-
-                        /* coding style*/
-                        fprintf(out_stream, "\t\t comp %d {\n", compno);
-                        fprintf(out_stream, "\t\t\t csty=%#x\n", l_tccp->csty);
-                        fprintf(out_stream, "\t\t\t numresolutions=%d\n", l_tccp->numresolutions);
-                        fprintf(out_stream, "\t\t\t cblkw=2^%d\n", l_tccp->cblkw);
-                        fprintf(out_stream, "\t\t\t cblkh=2^%d\n", l_tccp->cblkh);
-                        fprintf(out_stream, "\t\t\t cblksty=%#x\n", l_tccp->cblksty);
-                        fprintf(out_stream, "\t\t\t qmfbid=%d\n", l_tccp->qmfbid);
-
-                        fprintf(out_stream, "\t\t\t preccintsize (w,h)=");
-                        for (resno = 0; resno < l_tccp->numresolutions; resno++) {
-                                fprintf(out_stream, "(%d,%d) ", l_tccp->prcw[resno], l_tccp->prch[resno]);
-                        }
-                        fprintf(out_stream, "\n");
-
-                        /* quantization style*/
-                        fprintf(out_stream, "\t\t\t qntsty=%d\n", l_tccp->qntsty);
-                        fprintf(out_stream, "\t\t\t numgbits=%d\n", l_tccp->numgbits);
-                        fprintf(out_stream, "\t\t\t stepsizes (m,e)=");
-                        numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (OPJ_INT32)l_tccp->numresolutions * 3 - 2;
-                        for (bandno = 0; bandno < numbands; bandno++) {
-                                fprintf(out_stream, "(%d,%d) ", l_tccp->stepsizes[bandno].mant,
-                                        l_tccp->stepsizes[bandno].expn);
-                        }
-                        fprintf(out_stream, "\n");
-
-                        /* RGN value*/
-                        fprintf(out_stream, "\t\t\t roishift=%d\n", l_tccp->roishift);
-
-                        fprintf(out_stream, "\t\t }\n");
-                } /*end of component of default tile*/
-                fprintf(out_stream, "\t }\n"); /*end of default tile*/
-
-        }
-
+        opj_j2k_dump_tile_info(p_j2k->m_specific_param.m_decoder.m_default_tcp,(OPJ_INT32)p_j2k->m_private_image->numcomps, out_stream);
         fprintf(out_stream, "}\n");
-
 }
 
 void j2k_dump_image_header(opj_image_t* img_header, OPJ_BOOL dev_dump_flag, FILE* out_stream)
@@ -9049,7 +9517,7 @@ opj_codestream_index_t* j2k_get_cstr_index(opj_j2k_t* p_j2k)
         return l_cstr_index;
 }
 
-OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k)
 {
         OPJ_UINT32 it_tile=0;
 
@@ -9070,7 +9538,7 @@ OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k)
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
                                                             opj_stream_private_t *p_stream,
                                                             opj_event_mgr_t * p_manager)
 {
@@ -9089,7 +9557,7 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
         }
         l_max_data_size = 1000;
 
-        while (OPJ_TRUE) {
+               for (;;) {
                 if (! opj_j2k_read_tile_header( p_j2k,
                                         &l_current_tile_no,
                                         &l_data_size,
@@ -9120,6 +9588,7 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
 
                 if (! opj_j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) {
                         opj_free(l_current_data);
+                        opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile %d/%d\n", l_current_tile_no +1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
                         return OPJ_FALSE;
                 }
                 opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no +1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
@@ -9145,14 +9614,18 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
 /**
  * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures.
  */
-static void opj_j2k_setup_decoding (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_decoding (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions*/
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_tiles);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_tiles, p_manager)) {
+                return OPJ_FALSE;
+        }
         /* DEVELOPER CORNER, add your custom procedures */
 
+        return OPJ_TRUE;
 }
 
 /*
@@ -9211,7 +9684,7 @@ static OPJ_BOOL opj_j2k_decode_one_tile (       opj_j2k_t *p_j2k,
                                 p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT;
                 }
 
-        while (OPJ_TRUE) {
+               for (;;) {
                 if (! opj_j2k_read_tile_header( p_j2k,
                                         &l_current_tile_no,
                                         &l_data_size,
@@ -9278,14 +9751,18 @@ static OPJ_BOOL opj_j2k_decode_one_tile (       opj_j2k_t *p_j2k,
 /**
  * Sets up the procedures to do on decoding one tile. Developpers wanting to extend the library can add their own reading procedures.
  */
-static void opj_j2k_setup_decoding_tile (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_decoding_tile (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions*/
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_one_tile);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_one_tile, p_manager)) {
+                return OPJ_FALSE;
+        }
         /* DEVELOPER CORNER, add your custom procedures */
 
+        return OPJ_TRUE;
 }
 
 OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
@@ -9297,7 +9774,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
 
         if (!p_image)
                 return OPJ_FALSE;
-
+       
         p_j2k->m_output_image = opj_image_create0();
         if (! (p_j2k->m_output_image)) {
                 return OPJ_FALSE;
@@ -9305,7 +9782,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
         opj_copy_image_header(p_image, p_j2k->m_output_image);
 
         /* customization of the decoding */
-        opj_j2k_setup_decoding(p_j2k);
+        opj_j2k_setup_decoding(p_j2k, p_manager);
 
         /* Decode the codestream */
         if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) {
@@ -9318,6 +9795,13 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
         for (compno = 0; compno < p_image->numcomps; compno++) {
                 p_image->comps[compno].resno_decoded = p_j2k->m_output_image->comps[compno].resno_decoded;
                 p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
+#if 0
+                char fn[256];
+                sprintf( fn, "/tmp/%d.raw", compno );
+                FILE *debug = fopen( fn, "wb" );
+                fwrite( p_image->comps[compno].data, sizeof(OPJ_INT32), p_image->comps[compno].w * p_image->comps[compno].h, debug );
+                fclose( debug );
+#endif
                 p_j2k->m_output_image->comps[compno].data = NULL;
         }
 
@@ -9394,7 +9878,7 @@ OPJ_BOOL opj_j2k_get_tile(      opj_j2k_t *p_j2k,
         p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = (OPJ_INT32)tile_index;
 
         /* customization of the decoding */
-        opj_j2k_setup_decoding_tile(p_j2k);
+        opj_j2k_setup_decoding_tile(p_j2k, p_manager);
 
         /* Decode the codestream */
         if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) {
@@ -9451,50 +9935,81 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k,
                         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;
+                                                                                                       }
                         }
-                        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);
+
+                        /* 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,l_current_data,l_current_tile_size,p_stream,p_manager)) {
+                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;
 }
 
@@ -9503,7 +10018,9 @@ OPJ_BOOL opj_j2k_end_compress(  opj_j2k_t *p_j2k,
                                                         opj_event_mgr_t * p_manager)
 {
         /* customization of the encoding */
-        opj_j2k_setup_end_compress(p_j2k);
+        if (! opj_j2k_setup_end_compress(p_j2k, p_manager)) {
+                return OPJ_FALSE;
+        }
 
         if (! opj_j2k_exec (p_j2k, p_j2k->m_procedure_list, p_stream, p_manager))
         {
@@ -9524,6 +10041,10 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k,
         assert(p_manager != 00);
 
         p_j2k->m_private_image = opj_image_create0();
+        if (! p_j2k->m_private_image) {
+                opj_event_msg(p_manager, EVT_ERROR, "Failed to allocate image header." );
+                return OPJ_FALSE;
+        }
         opj_copy_image_header(p_image, p_j2k->m_private_image);
 
         /* TODO_MSD: Find a better way */
@@ -9539,7 +10060,9 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k,
         }
 
         /* customization of the validation */
-        opj_j2k_setup_encoding_validation (p_j2k);
+        if (! opj_j2k_setup_encoding_validation (p_j2k, p_manager)) {
+                return OPJ_FALSE;
+        }
 
         /* validation of the parameters codec */
         if (! opj_j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) {
@@ -9547,7 +10070,9 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k,
         }
 
         /* customization of the encoding */
-        opj_j2k_setup_header_writing(p_j2k);
+        if (! opj_j2k_setup_header_writing(p_j2k, p_manager)) {
+                return OPJ_FALSE;
+        }
 
         /* write header */
         if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) {
@@ -9557,7 +10082,7 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_pre_write_tile (       opj_j2k_t * p_j2k,
+static OPJ_BOOL opj_j2k_pre_write_tile (       opj_j2k_t * p_j2k,
                                                                 OPJ_UINT32 p_tile_index,
                                                                 opj_stream_private_t *p_stream,
                                                                 opj_event_mgr_t * p_manager )
@@ -9575,44 +10100,68 @@ OPJ_BOOL opj_j2k_pre_write_tile (       opj_j2k_t * p_j2k,
         p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0;
 
         /* initialisation before tile encoding  */
-        if (! opj_tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) {
+        if (! opj_tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number, p_manager)) {
                 return OPJ_FALSE;
         }
 
         return OPJ_TRUE;
 }
 
-void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data)
+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) {
+       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;
+}
+
+static 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:
@@ -9679,19 +10228,13 @@ void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data)
                                 }
                                 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,
+static OPJ_BOOL opj_j2k_post_write_tile (      opj_j2k_t * p_j2k,
                                                                 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;
@@ -9700,17 +10243,10 @@ OPJ_BOOL opj_j2k_post_write_tile (      opj_j2k_t * p_j2k,
         /* 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;
@@ -9737,79 +10273,133 @@ OPJ_BOOL opj_j2k_post_write_tile (      opj_j2k_t * p_j2k,
         return OPJ_TRUE;
 }
 
-void opj_j2k_setup_end_compress (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_end_compress (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions */
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
         /* DEVELOPER CORNER, insert your custom procedures */
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_eoc );
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_eoc, p_manager)) {
+                return OPJ_FALSE;
+        }
 
-        if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) {
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_updated_tlm);
+        if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) {
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_updated_tlm, p_manager)) {
+                        return OPJ_FALSE;
+                }
         }
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_epc );
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_end_encoding );
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_destroy_header_memory);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_epc, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_end_encoding, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_destroy_header_memory, p_manager)) {
+                return OPJ_FALSE;
+        }
+        return OPJ_TRUE;
 }
 
-void opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions */
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
-        opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_build_encoder);
-        opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_encoding_validation);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_build_encoder, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_encoding_validation, p_manager)) {
+                return OPJ_FALSE;
+                               }
 
         /* DEVELOPER CORNER, add your custom validation procedure */
-        opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_mct_validation);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_mct_validation, p_manager)) {
+                return OPJ_FALSE;
+        }
+       
+        return OPJ_TRUE;
 }
 
-void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k)
+static OPJ_BOOL opj_j2k_setup_header_writing (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager)
 {
         /* preconditions */
         assert(p_j2k != 00);
+        assert(p_manager != 00);
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_init_info );
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_soc );
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_siz );
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_cod );
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_qcd );
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_init_info, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_soc, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_siz, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_cod, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_qcd, p_manager)) {
+                return OPJ_FALSE;
+        }
 
-        if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) {
+        if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) {
                 /* No need for COC or QCC, QCD and COD are used
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_coc );
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_qcc );
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_coc, p_manager)) {
+                        return OPJ_FALSE;
+                }
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_qcc, p_manager)) {
+                        return OPJ_FALSE;
+                }
                 */
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_tlm );
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_tlm, p_manager)) {
+                        return OPJ_FALSE;
+                }
 
-                if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == OPJ_CINEMA4K_24) {
-                        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_poc );
+                if (p_j2k->m_cp.rsiz == OPJ_PROFILE_CINEMA_4K) {
+                        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_poc, p_manager)) {
+                                return OPJ_FALSE;
+                        }
                 }
         }
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_regions);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_regions, p_manager)) {
+                return OPJ_FALSE;
+        }
 
         if (p_j2k->m_cp.comment != 00)  {
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_com);
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_com, p_manager)) {
+                        return OPJ_FALSE;
+                }
         }
 
         /* DEVELOPER CORNER, insert your custom procedures */
-        if (p_j2k->m_cp.rsiz & OPJ_MCT) {
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_mct_data_group );
+        if (p_j2k->m_cp.rsiz & OPJ_EXTENSION_MCT) {
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_mct_data_group, p_manager)) {
+                        return OPJ_FALSE;
+                }
         }
         /* End of Developer Corner */
 
         if (p_j2k->cstr_index) {
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_get_end_header );
+                if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_get_end_header, p_manager)) {
+                        return OPJ_FALSE;
+                }
         }
 
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_create_tcd);
-        opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_update_rates);
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_create_tcd, p_manager)) {
+                return OPJ_FALSE;
+        }
+        if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_update_rates, p_manager)) {
+                return OPJ_FALSE;
+        }
+
+        return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k,
                                                                         OPJ_BYTE * p_data,
                                                                         OPJ_UINT32 * p_data_written,
                                                                         OPJ_UINT32 p_total_data_size,
@@ -9845,7 +10435,7 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k,
         p_data += l_current_nb_bytes_written;
         p_total_data_size -= l_current_nb_bytes_written;
 
-        if (l_cp->m_specific_param.m_enc.m_cinema == 0) {
+        if (!OPJ_IS_CINEMA(l_cp->rsiz)) {
 #if 0
                 for (compno = 1; compno < p_j2k->m_private_image->numcomps; compno++) {
                         l_current_nb_bytes_written = 0;
@@ -9882,14 +10472,14 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k,
         /* Writing Psot in SOT marker */
         opj_write_bytes(l_begin_data + 6,l_nb_bytes_written,4);                                 /* PSOT */
 
-        if (l_cp->m_specific_param.m_enc.m_cinema){
+        if (OPJ_IS_CINEMA(l_cp->rsiz)){
                 opj_j2k_update_tlm(p_j2k,l_nb_bytes_written);
         }
 
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
                                                                         OPJ_BYTE * p_data,
                                                                         OPJ_UINT32 * p_data_written,
                                                                         OPJ_UINT32 p_total_data_size,
@@ -9946,7 +10536,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
                 /* Writing Psot in SOT marker */
                 opj_write_bytes(l_begin_data + 6,l_part_tile_size,4);                                   /* PSOT */
 
-                if (l_cp->m_specific_param.m_enc.m_cinema) {
+                if (OPJ_IS_CINEMA(l_cp->rsiz)) {
                         opj_j2k_update_tlm(p_j2k,l_part_tile_size);
                 }
 
@@ -9987,7 +10577,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
                         /* Writing Psot in SOT marker */
                         opj_write_bytes(l_begin_data + 6,l_part_tile_size,4);                                   /* PSOT */
 
-                        if (l_cp->m_specific_param.m_enc.m_cinema) {
+                        if (OPJ_IS_CINEMA(l_cp->rsiz)) {
                                 opj_j2k_update_tlm(p_j2k,l_part_tile_size);
                         }
 
@@ -10000,7 +10590,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_updated_tlm( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_updated_tlm( opj_j2k_t *p_j2k,
                                                                     struct opj_stream_private *p_stream,
                                                                     struct opj_event_mgr * p_manager )
 {
@@ -10031,7 +10621,7 @@ OPJ_BOOL opj_j2k_write_updated_tlm( opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_end_encoding(  opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_end_encoding(  opj_j2k_t *p_j2k,
                                                         struct opj_stream_private *p_stream,
                                                         struct opj_event_mgr * p_manager )
 {
@@ -10082,7 +10672,7 @@ static OPJ_BOOL opj_j2k_destroy_header_memory ( opj_j2k_t * p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_init_info(     opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_init_info(     opj_j2k_t *p_j2k,
                                                 struct opj_stream_private *p_stream,
                                                 struct opj_event_mgr * p_manager )
 {
@@ -10181,7 +10771,23 @@ OPJ_BOOL opj_j2k_write_tile (opj_j2k_t * p_j2k,
                 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;
                 }