Fix warnings and errors when compiling with a c++ compiler (#1021)
[openjpeg.git] / src / lib / openjp2 / tcd.c
index 3a38ef42390e543818d7216ebec5656f6ecdfcca..fad9d23c02039d2b5a9b824aa5aeee218741b7c3 100644 (file)
@@ -14,6 +14,7 @@
  * Copyright (c) 2006-2007, Parvatha Elangovan
  * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR
  * Copyright (c) 2012, CS Systemes d'Information, France
+ * Copyright (c) 2017, IntoPIX SA <support@intopix.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -157,7 +158,8 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd,
                                   opj_codestream_index_t *p_cstr_index,
                                   opj_event_mgr_t *p_manager);
 
-static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd);
+static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd,
+                                  opj_event_mgr_t *p_manager);
 
 static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd);
 
@@ -179,12 +181,18 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd,
                                   OPJ_BYTE * p_dest_data,
                                   OPJ_UINT32 * p_data_written,
                                   OPJ_UINT32 p_max_dest_size,
-                                  opj_codestream_info_t *p_cstr_info);
+                                  opj_codestream_info_t *p_cstr_info,
+                                  opj_event_mgr_t *p_manager);
 
 static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd,
         OPJ_BYTE * p_dest_data,
         OPJ_UINT32 p_max_dest_size,
-        opj_codestream_info_t *p_cstr_info);
+        opj_codestream_info_t *p_cstr_info,
+        opj_event_mgr_t *p_manager);
+
+
+static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *tcd,
+        OPJ_UINT32 compno);
 
 /* ----------------------------------------------------------------------- */
 
@@ -265,28 +273,33 @@ void opj_tcd_makelayer(opj_tcd_t *tcd,
 
                         n = cblk->numpassesinlayers;
 
-                        for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) {
-                            OPJ_UINT32 dr;
-                            OPJ_FLOAT64 dd;
-                            opj_tcd_pass_t *pass = &cblk->passes[passno];
-
-                            if (n == 0) {
-                                dr = pass->rate;
-                                dd = pass->distortiondec;
-                            } else {
-                                dr = pass->rate - cblk->passes[n - 1].rate;
-                                dd = pass->distortiondec - cblk->passes[n - 1].distortiondec;
-                            }
+                        if (thresh < 0) {
+                            /* Special value to indicate to use all passes */
+                            n = cblk->totalpasses;
+                        } else {
+                            for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) {
+                                OPJ_UINT32 dr;
+                                OPJ_FLOAT64 dd;
+                                opj_tcd_pass_t *pass = &cblk->passes[passno];
+
+                                if (n == 0) {
+                                    dr = pass->rate;
+                                    dd = pass->distortiondec;
+                                } else {
+                                    dr = pass->rate - cblk->passes[n - 1].rate;
+                                    dd = pass->distortiondec - cblk->passes[n - 1].distortiondec;
+                                }
 
-                            if (!dr) {
-                                if (dd != 0) {
+                                if (!dr) {
+                                    if (dd != 0) {
+                                        n = passno + 1;
+                                    }
+                                    continue;
+                                }
+                                if (thresh - (dd / dr) <
+                                        DBL_EPSILON) { /* do not rely on float equality, check with DBL_EPSILON margin */
                                     n = passno + 1;
                                 }
-                                continue;
-                            }
-                            if (thresh - (dd / dr) <
-                                    DBL_EPSILON) { /* do not rely on float equality, check with DBL_EPSILON margin */
-                                n = passno + 1;
                             }
                         }
 
@@ -430,7 +443,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
                               OPJ_BYTE *dest,
                               OPJ_UINT32 * p_data_written,
                               OPJ_UINT32 len,
-                              opj_codestream_info_t *cstr_info)
+                              opj_codestream_info_t *cstr_info,
+                              opj_event_mgr_t *p_manager)
 {
     OPJ_UINT32 compno, resno, bandno, precno, cblkno, layno;
     OPJ_UINT32 passno;
@@ -562,7 +576,7 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
                     if (OPJ_IS_CINEMA(cp->rsiz)) {
                         if (! opj_t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest,
                                                     p_data_written, maxlen, cstr_info, tcd->cur_tp_num, tcd->tp_pos, tcd->cur_pino,
-                                                    THRESH_CALC)) {
+                                                    THRESH_CALC, p_manager)) {
 
                             lo = thresh;
                             continue;
@@ -592,7 +606,7 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
                 } else {
                     if (! opj_t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest,
                                                 p_data_written, maxlen, cstr_info, tcd->cur_tp_num, tcd->tp_pos, tcd->cur_pino,
-                                                THRESH_CALC)) {
+                                                THRESH_CALC, p_manager)) {
                         /* TODO: what to do with l ??? seek / tell ??? */
                         /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */
                         lo = thresh;
@@ -608,7 +622,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
 
             opj_t2_destroy(t2);
         } else {
-            goodthresh = min;
+            /* Special value to indicate to use all passes */
+            goodthresh = -1;
         }
 
         if (cstr_info) { /* Threshold for Marcela Index */
@@ -673,8 +688,8 @@ OPJ_BOOL opj_alloc_tile_component_data(opj_tcd_tilecomp_t *l_tilec)
     if ((l_tilec->data == 00) ||
             ((l_tilec->data_size_needed > l_tilec->data_size) &&
              (l_tilec->ownsData == OPJ_FALSE))) {
-        l_tilec->data = (OPJ_INT32 *) opj_aligned_malloc(l_tilec->data_size_needed);
-        if (! l_tilec->data) {
+        l_tilec->data = (OPJ_INT32 *) opj_image_data_alloc(l_tilec->data_size_needed);
+        if (!l_tilec->data && l_tilec->data_size_needed != 0) {
             return OPJ_FALSE;
         }
         /*fprintf(stderr, "tAllocate data of tilec (int): %d x OPJ_UINT32n",l_data_size);*/
@@ -682,8 +697,8 @@ OPJ_BOOL opj_alloc_tile_component_data(opj_tcd_tilecomp_t *l_tilec)
         l_tilec->ownsData = OPJ_TRUE;
     } else if (l_tilec->data_size_needed > l_tilec->data_size) {
         /* We don't need to keep old data */
-        opj_aligned_free(l_tilec->data);
-        l_tilec->data = (OPJ_INT32 *) opj_aligned_malloc(l_tilec->data_size_needed);
+        opj_image_data_free(l_tilec->data);
+        l_tilec->data = (OPJ_INT32 *) opj_image_data_alloc(l_tilec->data_size_needed);
         if (! l_tilec->data) {
             l_tilec->data_size = 0;
             l_tilec->data_size_needed = 0;
@@ -786,24 +801,9 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
         l_tilec->y0 = opj_int_ceildiv(l_tile->y0, (OPJ_INT32)l_image_comp->dy);
         l_tilec->x1 = opj_int_ceildiv(l_tile->x1, (OPJ_INT32)l_image_comp->dx);
         l_tilec->y1 = opj_int_ceildiv(l_tile->y1, (OPJ_INT32)l_image_comp->dy);
+        l_tilec->compno = compno;
         /*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/
 
-        /* compute l_data_size with overflow check */
-        l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
-        /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
-        if ((l_data_size > 0U) &&
-                ((((OPJ_UINT32) - 1) / l_data_size) < (OPJ_UINT32)(l_tilec->y1 -
-                        l_tilec->y0))) {
-            opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
-            return OPJ_FALSE;
-        }
-        l_data_size = l_data_size * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
-
-        if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) {
-            opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
-            return OPJ_FALSE;
-        }
-        l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32);
         l_tilec->numresolutions = l_tccp->numresolutions;
         if (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce) {
             l_tilec->minimum_num_resolutions = 1;
@@ -812,15 +812,39 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
                                                l_cp->m_specific_param.m_dec.m_reduce;
         }
 
-        l_tilec->data_size_needed = l_data_size;
-        if (p_tcd->m_is_decoder && !opj_alloc_tile_component_data(l_tilec)) {
-            opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
-            return OPJ_FALSE;
+        if (isEncoder) {
+            OPJ_SIZE_T l_tile_data_size;
+
+            /* compute l_data_size with overflow check */
+            OPJ_SIZE_T w = (OPJ_SIZE_T)(l_tilec->x1 - l_tilec->x0);
+            OPJ_SIZE_T h = (OPJ_SIZE_T)(l_tilec->y1 - l_tilec->y0);
+
+            /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
+            if (h > 0 && w > SIZE_MAX / h) {
+                opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n");
+                return OPJ_FALSE;
+            }
+            l_tile_data_size = w * h;
+
+            if (SIZE_MAX / sizeof(OPJ_UINT32) < l_tile_data_size) {
+                opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n");
+                return OPJ_FALSE;
+            }
+            l_tile_data_size = l_tile_data_size * sizeof(OPJ_UINT32);
+
+            l_tilec->data_size_needed = l_tile_data_size;
         }
 
         l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof(
                           opj_tcd_resolution_t);
 
+        opj_image_data_free(l_tilec->data_win);
+        l_tilec->data_win = NULL;
+        l_tilec->win_x0 = 0;
+        l_tilec->win_y0 = 0;
+        l_tilec->win_x1 = 0;
+        l_tilec->win_y1 = 0;
+
         if (l_tilec->resolutions == 00) {
             l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size);
             if (! l_tilec->resolutions) {
@@ -869,6 +893,7 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
             l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no);
             l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no);
             l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no);
+
             /*fprintf(stderr, "\t\t\tres_x0= %d, res_y0 =%d, res_x1=%d, res_y1=%d\n", l_res->x0, l_res->y0, l_res->x1, l_res->y1);*/
             /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */
             l_pdx = l_tccp->prcw[resno];
@@ -888,14 +913,14 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
             /*fprintf(stderr, "\t\t\tres_pw=%d, res_ph=%d\n", l_res->pw, l_res->ph );*/
 
             if ((l_res->pw != 0U) && ((((OPJ_UINT32) - 1) / l_res->pw) < l_res->ph)) {
-                opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
+                opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n");
                 return OPJ_FALSE;
             }
             l_nb_precincts = l_res->pw * l_res->ph;
 
             if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(opj_tcd_precinct_t)) <
                     l_nb_precincts) {
-                opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
+                opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n");
                 return OPJ_FALSE;
             }
             l_nb_precinct_size = l_nb_precincts * (OPJ_UINT32)sizeof(opj_tcd_precinct_t);
@@ -964,8 +989,10 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
                 numbps = (OPJ_INT32)(l_image_comp->prec + l_gain);
                 l_band->stepsize = (OPJ_FLOAT32)(((1.0 + l_step_size->mant / 2048.0) * pow(2.0,
                                                   (OPJ_INT32)(numbps - l_step_size->expn)))) * fraction;
+                /* Mb value of Equation E-2 in "E.1 Inverse quantization
+                 * procedure" of the standard */
                 l_band->numbps = l_step_size->expn + (OPJ_INT32)l_tccp->numgbits -
-                                 1;      /* WHY -1 ? */
+                                 1;
 
                 if (!l_band->precincts && (l_nb_precincts > 0U)) {
                     l_band->precincts = (opj_tcd_precinct_t *) opj_malloc(/*3 * */
@@ -1181,8 +1208,12 @@ static OPJ_BOOL opj_tcd_code_block_enc_allocate_data(opj_tcd_cblk_enc_t *
 {
     OPJ_UINT32 l_data_size;
 
-    l_data_size = (OPJ_UINT32)((p_code_block->x1 - p_code_block->x0) *
-                               (p_code_block->y1 - p_code_block->y0) * (OPJ_INT32)sizeof(OPJ_UINT32));
+    /* +1 is needed for https://github.com/uclouvain/openjpeg/issues/835 */
+    /* and actually +2 required for https://github.com/uclouvain/openjpeg/issues/982 */
+    /* TODO: is there a theoretical upper-bound for the compressed code */
+    /* block size ? */
+    l_data_size = 2 + (OPJ_UINT32)((p_code_block->x1 - p_code_block->x0) *
+                                   (p_code_block->y1 - p_code_block->y0) * (OPJ_INT32)sizeof(OPJ_UINT32));
 
     if (l_data_size > p_code_block->data_size) {
         if (p_code_block->data) {
@@ -1206,20 +1237,19 @@ static OPJ_BOOL opj_tcd_code_block_enc_allocate_data(opj_tcd_cblk_enc_t *
     return OPJ_TRUE;
 }
 
+
+void opj_tcd_reinit_segment(opj_tcd_seg_t* seg)
+{
+    memset(seg, 0, sizeof(opj_tcd_seg_t));
+}
+
 /**
  * Allocates memory for a decoding code block.
  */
 static OPJ_BOOL opj_tcd_code_block_dec_allocate(opj_tcd_cblk_dec_t *
         p_code_block)
 {
-    if (! p_code_block->data) {
-
-        p_code_block->data = (OPJ_BYTE*) opj_malloc(OPJ_COMMON_DEFAULT_CBLK_DATA_SIZE);
-        if (! p_code_block->data) {
-            return OPJ_FALSE;
-        }
-        p_code_block->data_max_size = OPJ_COMMON_DEFAULT_CBLK_DATA_SIZE;
-        /*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/
+    if (! p_code_block->segs) {
 
         p_code_block->segs = (opj_tcd_seg_t *) opj_calloc(OPJ_J2K_DEFAULT_NB_SEGS,
                              sizeof(opj_tcd_seg_t));
@@ -1232,22 +1262,30 @@ static OPJ_BOOL opj_tcd_code_block_dec_allocate(opj_tcd_cblk_dec_t *
         /*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/
     } else {
         /* sanitize */
-        OPJ_BYTE* l_data = p_code_block->data;
-        OPJ_UINT32 l_data_max_size = p_code_block->data_max_size;
         opj_tcd_seg_t * l_segs = p_code_block->segs;
         OPJ_UINT32 l_current_max_segs = p_code_block->m_current_max_segs;
+        opj_tcd_seg_data_chunk_t* l_chunks = p_code_block->chunks;
+        OPJ_UINT32 l_numchunksalloc = p_code_block->numchunksalloc;
+        OPJ_UINT32 i;
+
+        opj_aligned_free(p_code_block->decoded_data);
+        p_code_block->decoded_data = 00;
 
         memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t));
-        p_code_block->data = l_data;
-        p_code_block->data_max_size = l_data_max_size;
         p_code_block->segs = l_segs;
         p_code_block->m_current_max_segs = l_current_max_segs;
+        for (i = 0; i < l_current_max_segs; ++i) {
+            opj_tcd_reinit_segment(&l_segs[i]);
+        }
+        p_code_block->chunks = l_chunks;
+        p_code_block->numchunksalloc = l_numchunksalloc;
     }
 
     return OPJ_TRUE;
 }
 
-OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd)
+OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd,
+        OPJ_BOOL take_into_account_partial_decoding)
 {
     OPJ_UINT32 i;
     OPJ_UINT32 l_data_size = 0;
@@ -1255,11 +1293,13 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd)
     opj_tcd_tilecomp_t * l_tile_comp = 00;
     opj_tcd_resolution_t * l_res = 00;
     OPJ_UINT32 l_size_comp, l_remaining;
+    OPJ_UINT32 l_temp;
 
     l_tile_comp = p_tcd->tcd_image->tiles->comps;
     l_img_comp = p_tcd->image->comps;
 
     for (i = 0; i < p_tcd->image->numcomps; ++i) {
+        OPJ_UINT32 w, h;
         l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/
         l_remaining = l_img_comp->prec & 7;  /* (%8) */
 
@@ -1272,8 +1312,26 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd)
         }
 
         l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1;
-        l_data_size += l_size_comp * (OPJ_UINT32)((l_res->x1 - l_res->x0) *
-                       (l_res->y1 - l_res->y0));
+        if (take_into_account_partial_decoding && !p_tcd->whole_tile_decoding) {
+            w = l_res->win_x1 - l_res->win_x0;
+            h = l_res->win_y1 - l_res->win_y0;
+        } else {
+            w = (OPJ_UINT32)(l_res->x1 - l_res->x0);
+            h = (OPJ_UINT32)(l_res->y1 - l_res->y0);
+        }
+        if (h > 0 && UINT_MAX / w < h) {
+            return UINT_MAX;
+        }
+        l_temp = w * h;
+        if (l_size_comp && UINT_MAX / l_size_comp < l_temp) {
+            return UINT_MAX;
+        }
+        l_temp *= l_size_comp;
+
+        if (l_temp > UINT_MAX - l_data_size) {
+            return UINT_MAX;
+        }
+        l_data_size += l_temp;
         ++l_img_comp;
         ++l_tile_comp;
     }
@@ -1286,7 +1344,8 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
                              OPJ_BYTE *p_dest,
                              OPJ_UINT32 * p_data_written,
                              OPJ_UINT32 p_max_length,
-                             opj_codestream_info_t *p_cstr_info)
+                             opj_codestream_info_t *p_cstr_info,
+                             opj_event_mgr_t *p_manager)
 {
 
     if (p_tcd->cur_tp_num == 0) {
@@ -1313,7 +1372,8 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
                 p_cstr_info->tile[p_tile_no].pdy[i] = (int)l_tccp->prch[i];
             }
             p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t*) opj_calloc((
-                    size_t)p_cstr_info->numcomps * (size_t)p_cstr_info->numlayers * l_num_packs,
+                    OPJ_SIZE_T)p_cstr_info->numcomps * (OPJ_SIZE_T)p_cstr_info->numlayers *
+                                                  l_num_packs,
                                                   sizeof(opj_packet_info_t));
             if (!p_cstr_info->tile[p_tile_no].packet) {
                 /* FIXME event manager error callback */
@@ -1348,7 +1408,8 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
         /* FIXME _ProfStop(PGROUP_T1); */
 
         /* FIXME _ProfStart(PGROUP_RATE); */
-        if (! opj_tcd_rate_allocate_encode(p_tcd, p_dest, p_max_length, p_cstr_info)) {
+        if (! opj_tcd_rate_allocate_encode(p_tcd, p_dest, p_max_length,
+                                           p_cstr_info, p_manager)) {
             return OPJ_FALSE;
         }
         /* FIXME _ProfStop(PGROUP_RATE); */
@@ -1363,7 +1424,7 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
     /* FIXME _ProfStart(PGROUP_T2); */
 
     if (! opj_tcd_t2_encode(p_tcd, p_dest, p_data_written, p_max_length,
-                            p_cstr_info)) {
+                            p_cstr_info, p_manager)) {
         return OPJ_FALSE;
     }
     /* FIXME _ProfStop(PGROUP_T2); */
@@ -1374,6 +1435,10 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
 }
 
 OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
+                             OPJ_UINT32 win_x0,
+                             OPJ_UINT32 win_y0,
+                             OPJ_UINT32 win_x1,
+                             OPJ_UINT32 win_y1,
                              OPJ_BYTE *p_src,
                              OPJ_UINT32 p_max_length,
                              OPJ_UINT32 p_tile_no,
@@ -1382,8 +1447,102 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
                             )
 {
     OPJ_UINT32 l_data_read;
+    OPJ_UINT32 compno;
+
     p_tcd->tcd_tileno = p_tile_no;
     p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]);
+    p_tcd->win_x0 = win_x0;
+    p_tcd->win_y0 = win_y0;
+    p_tcd->win_x1 = win_x1;
+    p_tcd->win_y1 = win_y1;
+    p_tcd->whole_tile_decoding = OPJ_TRUE;
+
+    for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+        if (!opj_tcd_is_whole_tilecomp_decoding(p_tcd, compno)) {
+            p_tcd->whole_tile_decoding = OPJ_FALSE;
+            break;
+        }
+    }
+
+    if (p_tcd->whole_tile_decoding) {
+        for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+            opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+            opj_tcd_resolution_t *l_res = &
+                                          (tilec->resolutions[tilec->minimum_num_resolutions - 1]);
+            OPJ_SIZE_T l_data_size;
+
+            /* compute l_data_size with overflow check */
+            OPJ_SIZE_T res_w = (OPJ_SIZE_T)(l_res->x1 - l_res->x0);
+            OPJ_SIZE_T res_h = (OPJ_SIZE_T)(l_res->y1 - l_res->y0);
+
+            /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
+            if (res_h > 0 && res_w > SIZE_MAX / res_h) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Size of tile data exceeds system limits\n");
+                return OPJ_FALSE;
+            }
+            l_data_size = res_w * res_h;
+
+            if (SIZE_MAX / sizeof(OPJ_UINT32) < l_data_size) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Size of tile data exceeds system limits\n");
+                return OPJ_FALSE;
+            }
+            l_data_size *= sizeof(OPJ_UINT32);
+
+            tilec->data_size_needed = l_data_size;
+
+            if (!opj_alloc_tile_component_data(tilec)) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Size of tile data exceeds system limits\n");
+                return OPJ_FALSE;
+            }
+        }
+    } else {
+        /* Compute restricted tile-component and tile-resolution coordinates */
+        /* of the window of interest, but defer the memory allocation until */
+        /* we know the resno_decoded */
+        for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+            OPJ_UINT32 resno;
+            opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+            opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
+            /* Compute the intersection of the area of interest, expressed in tile coordinates */
+            /* with the tile coordinates */
+            tilec->win_x0 = opj_uint_max(
+                                (OPJ_UINT32)tilec->x0,
+                                opj_uint_ceildiv(p_tcd->win_x0, image_comp->dx));
+            tilec->win_y0 = opj_uint_max(
+                                (OPJ_UINT32)tilec->y0,
+                                opj_uint_ceildiv(p_tcd->win_y0, image_comp->dy));
+            tilec->win_x1 = opj_uint_min(
+                                (OPJ_UINT32)tilec->x1,
+                                opj_uint_ceildiv(p_tcd->win_x1, image_comp->dx));
+            tilec->win_y1 = opj_uint_min(
+                                (OPJ_UINT32)tilec->y1,
+                                opj_uint_ceildiv(p_tcd->win_y1, image_comp->dy));
+            if (tilec->win_x1 < tilec->win_x0 ||
+                    tilec->win_y1 < tilec->win_y0) {
+                /* We should not normally go there. The circumstance is when */
+                /* the tile coordinates do not intersect the area of interest */
+                /* Upper level logic should not even try to decode that tile */
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Invalid tilec->win_xxx values\n");
+                return OPJ_FALSE;
+            }
+
+            for (resno = 0; resno < tilec->numresolutions; ++resno) {
+                opj_tcd_resolution_t *res = tilec->resolutions + resno;
+                res->win_x0 = opj_uint_ceildivpow2(tilec->win_x0,
+                                                   tilec->numresolutions - 1 - resno);
+                res->win_y0 = opj_uint_ceildivpow2(tilec->win_y0,
+                                                   tilec->numresolutions - 1 - resno);
+                res->win_x1 = opj_uint_ceildivpow2(tilec->win_x1,
+                                                   tilec->numresolutions - 1 - resno);
+                res->win_y1 = opj_uint_ceildivpow2(tilec->win_y1,
+                                                   tilec->numresolutions - 1 - resno);
+            }
+        }
+    }
 
 #ifdef TODO_MSD /* FIXME */
     /* INDEX >>  */
@@ -1421,12 +1580,50 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
     /*------------------TIER1-----------------*/
 
     /* FIXME _ProfStart(PGROUP_T1); */
-    if
-    (! opj_tcd_t1_decode(p_tcd)) {
+    if (! opj_tcd_t1_decode(p_tcd, p_manager)) {
         return OPJ_FALSE;
     }
     /* FIXME _ProfStop(PGROUP_T1); */
 
+
+    /* For subtile decoding, now we know the resno_decoded, we can allocate */
+    /* the tile data buffer */
+    if (!p_tcd->whole_tile_decoding) {
+        for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+            opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+            opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
+            opj_tcd_resolution_t *res = tilec->resolutions + image_comp->resno_decoded;
+            OPJ_SIZE_T w = res->win_x1 - res->win_x0;
+            OPJ_SIZE_T h = res->win_y1 - res->win_y0;
+            OPJ_SIZE_T l_data_size;
+
+            opj_image_data_free(tilec->data_win);
+            tilec->data_win = NULL;
+
+            if (w > 0 && h > 0) {
+                if (w > SIZE_MAX / h) {
+                    opj_event_msg(p_manager, EVT_ERROR,
+                                  "Size of tile data exceeds system limits\n");
+                    return OPJ_FALSE;
+                }
+                l_data_size = w * h;
+                if (l_data_size > SIZE_MAX / sizeof(OPJ_INT32)) {
+                    opj_event_msg(p_manager, EVT_ERROR,
+                                  "Size of tile data exceeds system limits\n");
+                    return OPJ_FALSE;
+                }
+                l_data_size *= sizeof(OPJ_INT32);
+
+                tilec->data_win = (OPJ_INT32*) opj_image_data_alloc(l_data_size);
+                if (tilec->data_win == NULL) {
+                    opj_event_msg(p_manager, EVT_ERROR,
+                                  "Size of tile data exceeds system limits\n");
+                    return OPJ_FALSE;
+                }
+            }
+        }
+    }
+
     /*----------------DWT---------------------*/
 
     /* FIXME _ProfStart(PGROUP_DWT); */
@@ -1468,8 +1665,8 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
     OPJ_UINT32 l_size_comp, l_remaining;
     OPJ_UINT32 l_stride, l_width, l_height;
 
-    l_data_size = opj_tcd_get_decoded_tile_size(p_tcd);
-    if (l_data_size > p_dest_length) {
+    l_data_size = opj_tcd_get_decoded_tile_size(p_tcd, OPJ_TRUE);
+    if (l_data_size == UINT_MAX || l_data_size > p_dest_length) {
         return OPJ_FALSE;
     }
 
@@ -1477,12 +1674,23 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
     l_img_comp = p_tcd->image->comps;
 
     for (i = 0; i < p_tcd->image->numcomps; ++i) {
+        const OPJ_INT32* l_src_data;
         l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/
         l_remaining = l_img_comp->prec & 7;  /* (%8) */
         l_res = l_tilec->resolutions + l_img_comp->resno_decoded;
-        l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
-        l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
-        l_stride = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0) - l_width;
+        if (p_tcd->whole_tile_decoding) {
+            l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
+            l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
+            l_stride = (OPJ_UINT32)(l_tilec->resolutions[l_tilec->minimum_num_resolutions -
+                                                                     1].x1 -
+                                    l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x0) - l_width;
+            l_src_data = l_tilec->data;
+        } else {
+            l_width = l_res->win_x1 - l_res->win_x0;
+            l_height = l_res->win_y1 - l_res->win_y0;
+            l_stride = 0;
+            l_src_data = l_tilec->data_win;
+        }
 
         if (l_remaining) {
             ++l_size_comp;
@@ -1495,7 +1703,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
         switch (l_size_comp) {
         case 1: {
             OPJ_CHAR * l_dest_ptr = (OPJ_CHAR *) p_dest;
-            const OPJ_INT32 * l_src_ptr = l_tilec->data;
+            const OPJ_INT32 * l_src_ptr = l_src_data;
 
             if (l_img_comp->sgnd) {
                 for (j = 0; j < l_height; ++j) {
@@ -1517,20 +1725,24 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
         }
         break;
         case 2: {
-            const OPJ_INT32 * l_src_ptr = l_tilec->data;
+            const OPJ_INT32 * l_src_ptr = l_src_data;
             OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest;
 
             if (l_img_comp->sgnd) {
                 for (j = 0; j < l_height; ++j) {
                     for (k = 0; k < l_width; ++k) {
-                        *(l_dest_ptr++) = (OPJ_INT16)(*(l_src_ptr++));
+                        OPJ_INT16 val = (OPJ_INT16)(*(l_src_ptr++));
+                        memcpy(l_dest_ptr, &val, sizeof(val));
+                        l_dest_ptr ++;
                     }
                     l_src_ptr += l_stride;
                 }
             } else {
                 for (j = 0; j < l_height; ++j) {
                     for (k = 0; k < l_width; ++k) {
-                        *(l_dest_ptr++) = (OPJ_INT16)((*(l_src_ptr++)) & 0xffff);
+                        OPJ_INT16 val = (OPJ_INT16)((*(l_src_ptr++)) & 0xffff);
+                        memcpy(l_dest_ptr, &val, sizeof(val));
+                        l_dest_ptr ++;
                     }
                     l_src_ptr += l_stride;
                 }
@@ -1541,13 +1753,12 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
         break;
         case 4: {
             OPJ_INT32 * l_dest_ptr = (OPJ_INT32 *) p_dest;
-            OPJ_INT32 * l_src_ptr = l_tilec->data;
+            const OPJ_INT32 * l_src_ptr = l_src_data;
 
             for (j = 0; j < l_height; ++j) {
-                for (k = 0; k < l_width; ++k) {
-                    *(l_dest_ptr++) = (*(l_src_ptr++));
-                }
-                l_src_ptr += l_stride;
+                memcpy(l_dest_ptr, l_src_ptr, l_width * sizeof(OPJ_INT32));
+                l_dest_ptr += l_width;
+                l_src_ptr += l_width + l_stride;
             }
 
             p_dest = (OPJ_BYTE*) l_dest_ptr;
@@ -1601,14 +1812,16 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd)
         l_res = l_tile_comp->resolutions;
         if (l_res) {
 
-            l_nb_resolutions = l_tile_comp->resolutions_size / sizeof(opj_tcd_resolution_t);
+            l_nb_resolutions = l_tile_comp->resolutions_size / (OPJ_UINT32)sizeof(
+                                   opj_tcd_resolution_t);
             for (resno = 0; resno < l_nb_resolutions; ++resno) {
                 l_band = l_res->bands;
                 for (bandno = 0; bandno < 3; ++bandno) {
                     l_precinct = l_band->precincts;
                     if (l_precinct) {
 
-                        l_nb_precincts = l_band->precincts_data_size / sizeof(opj_tcd_precinct_t);
+                        l_nb_precincts = l_band->precincts_data_size / (OPJ_UINT32)sizeof(
+                                             opj_tcd_precinct_t);
                         for (precno = 0; precno < l_nb_precincts; ++precno) {
                             opj_tgt_destroy(l_precinct->incltree);
                             l_precinct->incltree = 00;
@@ -1631,12 +1844,15 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd)
         }
 
         if (l_tile_comp->ownsData && l_tile_comp->data) {
-            opj_aligned_free(l_tile_comp->data);
+            opj_image_data_free(l_tile_comp->data);
             l_tile_comp->data = 00;
             l_tile_comp->ownsData = 0;
             l_tile_comp->data_size = 0;
             l_tile_comp->data_size_needed = 0;
         }
+
+        opj_image_data_free(l_tile_comp->data_win);
+
         ++l_tile_comp;
     }
 
@@ -1663,6 +1879,7 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd,
     }
 
     if (! opj_t2_decode_packets(
+                p_tcd,
                 l_t2,
                 p_tcd->tcd_tileno,
                 p_tcd->tcd_image->tiles,
@@ -1681,16 +1898,27 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd,
     return OPJ_TRUE;
 }
 
-static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd)
+static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
 {
     OPJ_UINT32 compno;
     opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
     opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps;
     opj_tccp_t * l_tccp = p_tcd->tcp->tccps;
     volatile OPJ_BOOL ret = OPJ_TRUE;
+    OPJ_BOOL check_pterm = OPJ_FALSE;
+    opj_mutex_t* p_manager_mutex = NULL;
+
+    p_manager_mutex = opj_mutex_create();
+
+    /* Only enable PTERM check if we decode all layers */
+    if (p_tcd->tcp->num_layers_to_decode == p_tcd->tcp->numlayers &&
+            (l_tccp->cblksty & J2K_CCP_CBLKSTY_PTERM) != 0) {
+        check_pterm = OPJ_TRUE;
+    }
 
     for (compno = 0; compno < l_tile->numcomps; ++compno) {
-        opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp);
+        opj_t1_decode_cblks(p_tcd, &ret, l_tile_comp, l_tccp,
+                            p_manager, p_manager_mutex, check_pterm);
         if (!ret) {
             break;
         }
@@ -1699,7 +1927,9 @@ static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd)
     }
 
     opj_thread_pool_wait_completion(p_tcd->thread_pool, 0);
-
+    if (p_manager_mutex) {
+        opj_mutex_destroy(p_manager_mutex);
+    }
     return ret;
 }
 
@@ -1713,26 +1943,15 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd)
     opj_image_comp_t * l_img_comp = p_tcd->image->comps;
 
     for (compno = 0; compno < l_tile->numcomps; compno++) {
-        /*
-        if (tcd->cp->reduce != 0) {
-                tcd->image->comps[compno].resno_decoded =
-                        tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
-                if (tcd->image->comps[compno].resno_decoded < 0)
-                {
-                        return false;
-                }
-        }
-        numres2decode = tcd->image->comps[compno].resno_decoded + 1;
-        if(numres2decode > 0){
-        */
 
         if (l_tccp->qmfbid == 1) {
-            if (! opj_dwt_decode(p_tcd->thread_pool, l_tile_comp,
+            if (! opj_dwt_decode(p_tcd, l_tile_comp,
                                  l_img_comp->resno_decoded + 1)) {
                 return OPJ_FALSE;
             }
         } else {
-            if (! opj_dwt_decode_real(l_tile_comp, l_img_comp->resno_decoded + 1)) {
+            if (! opj_dwt_decode_real(p_tcd, l_tile_comp,
+                                      l_img_comp->resno_decoded + 1)) {
                 return OPJ_FALSE;
             }
         }
@@ -1744,6 +1963,7 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd)
 
     return OPJ_TRUE;
 }
+
 static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
 {
     opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
@@ -1755,21 +1975,73 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
         return OPJ_TRUE;
     }
 
-    l_samples = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) *
-                             (l_tile_comp->y1 - l_tile_comp->y0));
+    if (p_tcd->whole_tile_decoding) {
+        opj_tcd_resolution_t* res_comp0 = l_tile->comps[0].resolutions +
+                                          l_tile_comp->minimum_num_resolutions - 1;
+
+        /* A bit inefficient: we process more data than needed if */
+        /* resno_decoded < l_tile_comp->minimum_num_resolutions-1, */
+        /* but we would need to take into account a stride then */
+        l_samples = (OPJ_UINT32)((res_comp0->x1 - res_comp0->x0) *
+                                 (res_comp0->y1 - res_comp0->y0));
+        if (l_tile->numcomps >= 3) {
+            if (l_tile_comp->minimum_num_resolutions !=
+                    l_tile->comps[1].minimum_num_resolutions ||
+                    l_tile_comp->minimum_num_resolutions !=
+                    l_tile->comps[2].minimum_num_resolutions) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Tiles don't all have the same dimension. Skip the MCT step.\n");
+                return OPJ_FALSE;
+            }
+        }
+        if (l_tile->numcomps >= 3) {
+            opj_tcd_resolution_t* res_comp1 = l_tile->comps[1].resolutions +
+                                              l_tile_comp->minimum_num_resolutions - 1;
+            opj_tcd_resolution_t* res_comp2 = l_tile->comps[2].resolutions +
+                                              l_tile_comp->minimum_num_resolutions - 1;
+            /* testcase 1336.pdf.asan.47.376 */
+            if (p_tcd->image->comps[0].resno_decoded !=
+                    p_tcd->image->comps[1].resno_decoded ||
+                    p_tcd->image->comps[0].resno_decoded !=
+                    p_tcd->image->comps[2].resno_decoded ||
+                    (OPJ_SIZE_T)(res_comp1->x1 - res_comp1->x0) *
+                    (OPJ_SIZE_T)(res_comp1->y1 - res_comp1->y0) != l_samples ||
+                    (OPJ_SIZE_T)(res_comp2->x1 - res_comp2->x0) *
+                    (OPJ_SIZE_T)(res_comp2->y1 - res_comp2->y0) != l_samples) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Tiles don't all have the same dimension. Skip the MCT step.\n");
+                return OPJ_FALSE;
+            }
+        }
+    } else {
+        opj_tcd_resolution_t* res_comp0 = l_tile->comps[0].resolutions +
+                                          p_tcd->image->comps[0].resno_decoded;
+
+        l_samples = (res_comp0->win_x1 - res_comp0->win_x0) *
+                    (res_comp0->win_y1 - res_comp0->win_y0);
+        if (l_tile->numcomps >= 3) {
+            opj_tcd_resolution_t* res_comp1 = l_tile->comps[1].resolutions +
+                                              p_tcd->image->comps[1].resno_decoded;
+            opj_tcd_resolution_t* res_comp2 = l_tile->comps[2].resolutions +
+                                              p_tcd->image->comps[2].resno_decoded;
+            /* testcase 1336.pdf.asan.47.376 */
+            if (p_tcd->image->comps[0].resno_decoded !=
+                    p_tcd->image->comps[1].resno_decoded ||
+                    p_tcd->image->comps[0].resno_decoded !=
+                    p_tcd->image->comps[2].resno_decoded ||
+                    (OPJ_SIZE_T)(res_comp1->win_x1 - res_comp1->win_x0) *
+                    (OPJ_SIZE_T)(res_comp1->win_y1 - res_comp1->win_y0) != l_samples ||
+                    (OPJ_SIZE_T)(res_comp2->win_x1 - res_comp2->win_x0) *
+                    (OPJ_SIZE_T)(res_comp2->win_y1 - res_comp2->win_y0) != l_samples) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "Tiles don't all have the same dimension. Skip the MCT step.\n");
+                return OPJ_FALSE;
+            }
+        }
+    }
 
     if (l_tile->numcomps >= 3) {
-        /* testcase 1336.pdf.asan.47.376 */
-        if ((l_tile->comps[0].x1 - l_tile->comps[0].x0) * (l_tile->comps[0].y1 -
-                l_tile->comps[0].y0) < (OPJ_INT32)l_samples ||
-                (l_tile->comps[1].x1 - l_tile->comps[1].x0) * (l_tile->comps[1].y1 -
-                        l_tile->comps[1].y0) < (OPJ_INT32)l_samples ||
-                (l_tile->comps[2].x1 - l_tile->comps[2].x0) * (l_tile->comps[2].y1 -
-                        l_tile->comps[2].y0) < (OPJ_INT32)l_samples) {
-            opj_event_msg(p_manager, EVT_ERROR,
-                          "Tiles don't all have the same dimension. Skip the MCT step.\n");
-            return OPJ_FALSE;
-        } else if (l_tcp->mct == 2) {
+        if (l_tcp->mct == 2) {
             OPJ_BYTE ** l_data;
 
             if (! l_tcp->m_mct_decoding_matrix) {
@@ -1782,7 +2054,11 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
             }
 
             for (i = 0; i < l_tile->numcomps; ++i) {
-                l_data[i] = (OPJ_BYTE*) l_tile_comp->data;
+                if (p_tcd->whole_tile_decoding) {
+                    l_data[i] = (OPJ_BYTE*) l_tile_comp->data;
+                } else {
+                    l_data[i] = (OPJ_BYTE*) l_tile_comp->data_win;
+                }
                 ++l_tile_comp;
             }
 
@@ -1803,15 +2079,29 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
             opj_free(l_data);
         } else {
             if (l_tcp->tccps->qmfbid == 1) {
-                opj_mct_decode(l_tile->comps[0].data,
-                               l_tile->comps[1].data,
-                               l_tile->comps[2].data,
-                               l_samples);
+                if (p_tcd->whole_tile_decoding) {
+                    opj_mct_decode(l_tile->comps[0].data,
+                                   l_tile->comps[1].data,
+                                   l_tile->comps[2].data,
+                                   l_samples);
+                } else {
+                    opj_mct_decode(l_tile->comps[0].data_win,
+                                   l_tile->comps[1].data_win,
+                                   l_tile->comps[2].data_win,
+                                   l_samples);
+                }
             } else {
-                opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data,
-                                    (OPJ_FLOAT32*)l_tile->comps[1].data,
-                                    (OPJ_FLOAT32*)l_tile->comps[2].data,
-                                    l_samples);
+                if (p_tcd->whole_tile_decoding) {
+                    opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data,
+                                        (OPJ_FLOAT32*)l_tile->comps[1].data,
+                                        (OPJ_FLOAT32*)l_tile->comps[2].data,
+                                        l_samples);
+                } else {
+                    opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data_win,
+                                        (OPJ_FLOAT32*)l_tile->comps[1].data_win,
+                                        (OPJ_FLOAT32*)l_tile->comps[2].data_win,
+                                        l_samples);
+                }
             }
         }
     } else {
@@ -1844,26 +2134,38 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd)
 
     for (compno = 0; compno < l_tile->numcomps; compno++) {
         l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded;
-        l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
-        l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
-        l_stride = (OPJ_UINT32)(l_tile_comp->x1 - l_tile_comp->x0) - l_width;
 
-        assert(l_height == 0 ||
-               l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/
+        if (!p_tcd->whole_tile_decoding) {
+            l_width = l_res->win_x1 - l_res->win_x0;
+            l_height = l_res->win_y1 - l_res->win_y0;
+            l_stride = 0;
+            l_current_ptr = l_tile_comp->data_win;
+        } else {
+            l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
+            l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
+            l_stride = (OPJ_UINT32)(
+                           l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x1 -
+                           l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x0)
+                       - l_width;
+            l_current_ptr = l_tile_comp->data;
+
+            assert(l_height == 0 ||
+                   l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/
+        }
 
         if (l_img_comp->sgnd) {
             l_min = -(1 << (l_img_comp->prec - 1));
             l_max = (1 << (l_img_comp->prec - 1)) - 1;
         } else {
             l_min = 0;
-            l_max = (1 << l_img_comp->prec) - 1;
+            l_max = (OPJ_INT32)((1U << l_img_comp->prec) - 1);
         }
 
-        l_current_ptr = l_tile_comp->data;
 
         if (l_tccp->qmfbid == 1) {
             for (j = 0; j < l_height; ++j) {
                 for (i = 0; i < l_width; ++i) {
+                    /* TODO: do addition on int64 ? */
                     *l_current_ptr = opj_int_clamp(*l_current_ptr + l_tccp->m_dc_level_shift, l_min,
                                                    l_max);
                     ++l_current_ptr;
@@ -1874,8 +2176,16 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd)
             for (j = 0; j < l_height; ++j) {
                 for (i = 0; i < l_width; ++i) {
                     OPJ_FLOAT32 l_value = *((OPJ_FLOAT32 *) l_current_ptr);
-                    *l_current_ptr = opj_int_clamp((OPJ_INT32)opj_lrintf(l_value) +
-                                                   l_tccp->m_dc_level_shift, l_min, l_max); ;
+                    if (l_value > INT_MAX) {
+                        *l_current_ptr = l_max;
+                    } else if (l_value < INT_MIN) {
+                        *l_current_ptr = l_min;
+                    } else {
+                        /* Do addition on int64 to avoid overflows */
+                        OPJ_INT64 l_value_int = (OPJ_INT64)opj_lrintf(l_value);
+                        *l_current_ptr = (OPJ_INT32)opj_int64_clamp(
+                                             l_value_int + l_tccp->m_dc_level_shift, l_min, l_max);
+                    }
                     ++l_current_ptr;
                 }
                 l_current_ptr += l_stride;
@@ -1907,21 +2217,25 @@ static void opj_tcd_code_block_dec_deallocate(opj_tcd_precinct_t * p_precinct)
                         l_code_block->numbps, l_code_block->numlenbits, l_code_block->len, l_code_block->numnewpasses, l_code_block->real_num_segs, l_code_block->m_current_max_segs );*/
 
 
-        l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_dec_t);
+        l_nb_code_blocks = p_precinct->block_size / (OPJ_UINT32)sizeof(
+                               opj_tcd_cblk_dec_t);
         /*fprintf(stderr,"nb_code_blocks =%d\t}\n", l_nb_code_blocks);*/
 
         for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) {
 
-            if (l_code_block->data) {
-                opj_free(l_code_block->data);
-                l_code_block->data = 00;
-            }
-
             if (l_code_block->segs) {
                 opj_free(l_code_block->segs);
                 l_code_block->segs = 00;
             }
 
+            if (l_code_block->chunks) {
+                opj_free(l_code_block->chunks);
+                l_code_block->chunks = 00;
+            }
+
+            opj_aligned_free(l_code_block->decoded_data);
+            l_code_block->decoded_data = NULL;
+
             ++l_code_block;
         }
 
@@ -1939,7 +2253,8 @@ static void opj_tcd_code_block_enc_deallocate(opj_tcd_precinct_t * p_precinct)
 
     opj_tcd_cblk_enc_t * l_code_block = p_precinct->cblks.enc;
     if (l_code_block) {
-        l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_enc_t);
+        l_nb_code_blocks = p_precinct->block_size / (OPJ_UINT32)sizeof(
+                               opj_tcd_cblk_enc_t);
 
         for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno)  {
             if (l_code_block->data) {
@@ -1967,9 +2282,10 @@ static void opj_tcd_code_block_enc_deallocate(opj_tcd_precinct_t * p_precinct)
     }
 }
 
-OPJ_UINT32 opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd)
+OPJ_SIZE_T opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd)
 {
-    OPJ_UINT32 i, l_data_size = 0;
+    OPJ_UINT32 i;
+    OPJ_SIZE_T l_data_size = 0;
     opj_image_comp_t * l_img_comp = 00;
     opj_tcd_tilecomp_t * l_tilec = 00;
     OPJ_UINT32 l_size_comp, l_remaining;
@@ -1988,8 +2304,8 @@ OPJ_UINT32 opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd)
             l_size_comp = 4;
         }
 
-        l_data_size += l_size_comp * (OPJ_UINT32)((l_tilec->x1 - l_tilec->x0) *
-                       (l_tilec->y1 - l_tilec->y0));
+        l_data_size += l_size_comp * ((OPJ_SIZE_T)(l_tilec->x1 - l_tilec->x0) *
+                                      (OPJ_SIZE_T)(l_tilec->y1 - l_tilec->y0));
         ++l_img_comp;
         ++l_tilec;
     }
@@ -2004,7 +2320,7 @@ static OPJ_BOOL opj_tcd_dc_level_shift_encode(opj_tcd_t *p_tcd)
     opj_tccp_t * l_tccp = 00;
     opj_image_comp_t * l_img_comp = 00;
     opj_tcd_tile_t * l_tile;
-    OPJ_UINT32 l_nb_elem, i;
+    OPJ_SIZE_T l_nb_elem, i;
     OPJ_INT32 * l_current_ptr;
 
     l_tile = p_tcd->tcd_image->tiles;
@@ -2014,8 +2330,8 @@ static OPJ_BOOL opj_tcd_dc_level_shift_encode(opj_tcd_t *p_tcd)
 
     for (compno = 0; compno < l_tile->numcomps; compno++) {
         l_current_ptr = l_tile_comp->data;
-        l_nb_elem = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) *
-                                 (l_tile_comp->y1 - l_tile_comp->y0));
+        l_nb_elem = (OPJ_SIZE_T)(l_tile_comp->x1 - l_tile_comp->x0) *
+                    (OPJ_SIZE_T)(l_tile_comp->y1 - l_tile_comp->y0);
 
         if (l_tccp->qmfbid == 1) {
             for (i = 0; i < l_nb_elem; ++i) {
@@ -2041,8 +2357,8 @@ static OPJ_BOOL opj_tcd_mct_encode(opj_tcd_t *p_tcd)
 {
     opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
     opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps;
-    OPJ_UINT32 samples = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) *
-                                      (l_tile_comp->y1 - l_tile_comp->y0));
+    OPJ_SIZE_T samples = (OPJ_SIZE_T)(l_tile_comp->x1 - l_tile_comp->x0) *
+                         (OPJ_SIZE_T)(l_tile_comp->y1 - l_tile_comp->y0);
     OPJ_UINT32 i;
     OPJ_BYTE ** l_data = 00;
     opj_tcp_t * l_tcp = p_tcd->tcp;
@@ -2157,7 +2473,8 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd,
                                   OPJ_BYTE * p_dest_data,
                                   OPJ_UINT32 * p_data_written,
                                   OPJ_UINT32 p_max_dest_size,
-                                  opj_codestream_info_t *p_cstr_info)
+                                  opj_codestream_info_t *p_cstr_info,
+                                  opj_event_mgr_t *p_manager)
 {
     opj_t2_t * l_t2;
 
@@ -2178,7 +2495,8 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd,
                 p_tcd->tp_num,
                 p_tcd->tp_pos,
                 p_tcd->cur_pino,
-                FINAL_PASS)) {
+                FINAL_PASS,
+                p_manager)) {
         opj_t2_destroy(l_t2);
         return OPJ_FALSE;
     }
@@ -2193,7 +2511,8 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd,
 static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd,
         OPJ_BYTE * p_dest_data,
         OPJ_UINT32 p_max_dest_size,
-        opj_codestream_info_t *p_cstr_info)
+        opj_codestream_info_t *p_cstr_info,
+        opj_event_mgr_t *p_manager)
 {
     opj_cp_t * l_cp = p_tcd->cp;
     OPJ_UINT32 l_nb_written = 0;
@@ -2207,7 +2526,7 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd,
         /* fixed_quality */
         /* Normal Rate/distortion allocation */
         if (! opj_tcd_rateallocate(p_tcd, p_dest_data, &l_nb_written, p_max_dest_size,
-                                   p_cstr_info)) {
+                                   p_cstr_info, p_manager)) {
             return OPJ_FALSE;
         }
     } else {
@@ -2221,13 +2540,15 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd,
 
 OPJ_BOOL opj_tcd_copy_tile_data(opj_tcd_t *p_tcd,
                                 OPJ_BYTE * p_src,
-                                OPJ_UINT32 p_src_length)
+                                OPJ_SIZE_T p_src_length)
 {
-    OPJ_UINT32 i, j, l_data_size = 0;
+    OPJ_UINT32 i;
+    OPJ_SIZE_T j;
+    OPJ_SIZE_T l_data_size = 0;
     opj_image_comp_t * l_img_comp = 00;
     opj_tcd_tilecomp_t * l_tilec = 00;
     OPJ_UINT32 l_size_comp, l_remaining;
-    OPJ_UINT32 l_nb_elem;
+    OPJ_SIZE_T l_nb_elem;
 
     l_data_size = opj_tcd_get_encoded_tile_size(p_tcd);
     if (l_data_size != p_src_length) {
@@ -2239,8 +2560,8 @@ OPJ_BOOL opj_tcd_copy_tile_data(opj_tcd_t *p_tcd,
     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) */
-        l_nb_elem = (OPJ_UINT32)((l_tilec->x1 - l_tilec->x0) * (l_tilec->y1 -
-                                 l_tilec->y0));
+        l_nb_elem = (OPJ_SIZE_T)(l_tilec->x1 - l_tilec->x0) *
+                    (OPJ_SIZE_T)(l_tilec->y1 - l_tilec->y0);
 
         if (l_remaining) {
             ++l_size_comp;
@@ -2309,3 +2630,125 @@ OPJ_BOOL opj_tcd_is_band_empty(opj_tcd_band_t* band)
 {
     return (band->x1 - band->x0 == 0) || (band->y1 - band->y0 == 0);
 }
+
+OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
+        OPJ_UINT32 compno,
+        OPJ_UINT32 resno,
+        OPJ_UINT32 bandno,
+        OPJ_UINT32 band_x0,
+        OPJ_UINT32 band_y0,
+        OPJ_UINT32 band_x1,
+        OPJ_UINT32 band_y1)
+{
+    /* Note: those values for filter_margin are in part the result of */
+    /* experimentation. The value 2 for QMFBID=1 (5x3 filter) can be linked */
+    /* to the maximum left/right extension given in tables F.2 and F.3 of the */
+    /* standard. The value 3 for QMFBID=0 (9x7 filter) is more suspicious, */
+    /* since F.2 and F.3 would lead to 4 instead, so the current 3 might be */
+    /* needed to be bumped to 4, in case inconsistencies are found while */
+    /* decoding parts of irreversible coded images. */
+    /* See opj_dwt_decode_partial_53 and opj_dwt_decode_partial_97 as well */
+    OPJ_UINT32 filter_margin = (tcd->tcp->tccps[compno].qmfbid == 1) ? 2 : 3;
+    opj_tcd_tilecomp_t *tilec = &(tcd->tcd_image->tiles->comps[compno]);
+    opj_image_comp_t* image_comp = &(tcd->image->comps[compno]);
+    /* Compute the intersection of the area of interest, expressed in tile coordinates */
+    /* with the tile coordinates */
+    OPJ_UINT32 tcx0 = opj_uint_max(
+                          (OPJ_UINT32)tilec->x0,
+                          opj_uint_ceildiv(tcd->win_x0, image_comp->dx));
+    OPJ_UINT32 tcy0 = opj_uint_max(
+                          (OPJ_UINT32)tilec->y0,
+                          opj_uint_ceildiv(tcd->win_y0, image_comp->dy));
+    OPJ_UINT32 tcx1 = opj_uint_min(
+                          (OPJ_UINT32)tilec->x1,
+                          opj_uint_ceildiv(tcd->win_x1, image_comp->dx));
+    OPJ_UINT32 tcy1 = opj_uint_min(
+                          (OPJ_UINT32)tilec->y1,
+                          opj_uint_ceildiv(tcd->win_y1, image_comp->dy));
+    /* Compute number of decomposition for this band. See table F-1 */
+    OPJ_UINT32 nb = (resno == 0) ?
+                    tilec->numresolutions - 1 :
+                    tilec->numresolutions - resno;
+    /* Map above tile-based coordinates to sub-band-based coordinates per */
+    /* equation B-15 of the standard */
+    OPJ_UINT32 x0b = bandno & 1;
+    OPJ_UINT32 y0b = bandno >> 1;
+    OPJ_UINT32 tbx0 = (nb == 0) ? tcx0 :
+                      (tcx0 <= (1U << (nb - 1)) * x0b) ? 0 :
+                      opj_uint_ceildivpow2(tcx0 - (1U << (nb - 1)) * x0b, nb);
+    OPJ_UINT32 tby0 = (nb == 0) ? tcy0 :
+                      (tcy0 <= (1U << (nb - 1)) * y0b) ? 0 :
+                      opj_uint_ceildivpow2(tcy0 - (1U << (nb - 1)) * y0b, nb);
+    OPJ_UINT32 tbx1 = (nb == 0) ? tcx1 :
+                      (tcx1 <= (1U << (nb - 1)) * x0b) ? 0 :
+                      opj_uint_ceildivpow2(tcx1 - (1U << (nb - 1)) * x0b, nb);
+    OPJ_UINT32 tby1 = (nb == 0) ? tcy1 :
+                      (tcy1 <= (1U << (nb - 1)) * y0b) ? 0 :
+                      opj_uint_ceildivpow2(tcy1 - (1U << (nb - 1)) * y0b, nb);
+    OPJ_BOOL intersects;
+
+    if (tbx0 < filter_margin) {
+        tbx0 = 0;
+    } else {
+        tbx0 -= filter_margin;
+    }
+    if (tby0 < filter_margin) {
+        tby0 = 0;
+    } else {
+        tby0 -= filter_margin;
+    }
+    tbx1 = opj_uint_adds(tbx1, filter_margin);
+    tby1 = opj_uint_adds(tby1, filter_margin);
+
+    intersects = band_x0 < tbx1 && band_y0 < tby1 && band_x1 > tbx0 &&
+                 band_y1 > tby0;
+
+#ifdef DEBUG_VERBOSE
+    printf("compno=%u resno=%u nb=%u bandno=%u x0b=%u y0b=%u band=%u,%u,%u,%u tb=%u,%u,%u,%u -> %u\n",
+           compno, resno, nb, bandno, x0b, y0b,
+           band_x0, band_y0, band_x1, band_y1,
+           tbx0, tby0, tbx1, tby1, intersects);
+#endif
+    return intersects;
+}
+
+/** Returns whether a tile componenent is fully decoded, taking into account
+ * p_tcd->win_* members.
+ *
+ * @param p_tcd    TCD handle.
+ * @param compno Component number
+ * @return OPJ_TRUE whether the tile componenent is fully decoded
+ */
+static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *p_tcd,
+        OPJ_UINT32 compno)
+{
+    opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+    opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
+    /* Compute the intersection of the area of interest, expressed in tile coordinates */
+    /* with the tile coordinates */
+    OPJ_UINT32 tcx0 = opj_uint_max(
+                          (OPJ_UINT32)tilec->x0,
+                          opj_uint_ceildiv(p_tcd->win_x0, image_comp->dx));
+    OPJ_UINT32 tcy0 = opj_uint_max(
+                          (OPJ_UINT32)tilec->y0,
+                          opj_uint_ceildiv(p_tcd->win_y0, image_comp->dy));
+    OPJ_UINT32 tcx1 = opj_uint_min(
+                          (OPJ_UINT32)tilec->x1,
+                          opj_uint_ceildiv(p_tcd->win_x1, image_comp->dx));
+    OPJ_UINT32 tcy1 = opj_uint_min(
+                          (OPJ_UINT32)tilec->y1,
+                          opj_uint_ceildiv(p_tcd->win_y1, image_comp->dy));
+
+    OPJ_UINT32 shift = tilec->numresolutions - tilec->minimum_num_resolutions;
+    /* Tolerate small margin within the reduced resolution factor to consider if */
+    /* the whole tile path must be taken */
+    return (tcx0 >= (OPJ_UINT32)tilec->x0 &&
+            tcy0 >= (OPJ_UINT32)tilec->y0 &&
+            tcx1 <= (OPJ_UINT32)tilec->x1 &&
+            tcy1 <= (OPJ_UINT32)tilec->y1 &&
+            (shift >= 32 ||
+             (((tcx0 - (OPJ_UINT32)tilec->x0) >> shift) == 0 &&
+              ((tcy0 - (OPJ_UINT32)tilec->y0) >> shift) == 0 &&
+              (((OPJ_UINT32)tilec->x1 - tcx1) >> shift) == 0 &&
+              (((OPJ_UINT32)tilec->y1 - tcy1) >> shift) == 0)));
+}