opj_j2k_update_rates(): grow tile size buffer for some situations
[openjpeg.git] / src / lib / openjp2 / j2k.c
index ce7fe019b02a89fb3464fa323ac94c1fff185103..55ca5813d29c1d5af99ea83ae2d8bd105979986c 100644 (file)
@@ -16,6 +16,7 @@
  * Copyright (c) 2010-2011, Kaori Hagihara
  * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
  * 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
@@ -832,13 +833,15 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k,
  * Writes the SOT marker (Start of tile-part)
  *
  * @param       p_j2k            J2K codec.
- * @param       p_data           FIXME DOC
- * @param       p_data_written   FIXME DOC
+ * @param       p_data           Output buffer
+ * @param       p_total_data_size Output buffer size
+ * @param       p_data_written   Number of bytes written into stream
  * @param       p_stream         the stream to write data to.
  * @param       p_manager        the user event manager.
 */
 static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
                                   OPJ_BYTE * p_data,
+                                  OPJ_UINT32 p_total_data_size,
                                   OPJ_UINT32 * p_data_written,
                                   const opj_stream_private_t *p_stream,
                                   opj_event_mgr_t * p_manager);
@@ -1305,7 +1308,7 @@ typedef struct j2k_prog_order {
     char str_prog[5];
 } j2k_prog_order_t;
 
-static j2k_prog_order_t j2k_prog_order_list[] = {
+static const j2k_prog_order_t j2k_prog_order_list[] = {
     {OPJ_CPRL, "CPRL"},
     {OPJ_LRCP, "LRCP"},
     {OPJ_PCRL, "PCRL"},
@@ -1602,9 +1605,9 @@ static void  opj_j2k_write_float_to_float64(const void * p_src_data,
     }
 }
 
-char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order)
+const char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order)
 {
-    j2k_prog_order_t *po;
+    const j2k_prog_order_t *po;
     for (po = j2k_prog_order_list; po->enum_prog != -1; po++) {
         if (po->enum_prog == prg_order) {
             return po->str_prog;
@@ -2054,6 +2057,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
     OPJ_UINT32 l_remaining_size;
     OPJ_UINT32 l_nb_tiles;
     OPJ_UINT32 l_tmp, l_tx1, l_ty1;
+    OPJ_UINT32 l_prec0, l_sgnd0;
     opj_image_t *l_image = 00;
     opj_cp_t *l_cp = 00;
     opj_image_comp_t * l_img_comp = 00;
@@ -2156,7 +2160,20 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                       "Error with SIZ marker: illegal tile offset\n");
         return OPJ_FALSE;
     }
+    if (!p_j2k->dump_state) {
+        OPJ_UINT32 siz_w, siz_h;
+
+        siz_w = l_image->x1 - l_image->x0;
+        siz_h = l_image->y1 - l_image->y0;
 
+        if (p_j2k->ihdr_w > 0 && p_j2k->ihdr_h > 0
+                && (p_j2k->ihdr_w != siz_w || p_j2k->ihdr_h != siz_h)) {
+            opj_event_msg(p_manager, EVT_ERROR,
+                          "Error with SIZ marker: IHDR w(%u) h(%u) vs. SIZ w(%u) h(%u)\n", p_j2k->ihdr_w,
+                          p_j2k->ihdr_h, siz_w, siz_h);
+            return OPJ_FALSE;
+        }
+    }
 #ifdef USE_JPWL
     if (l_cp->correct) {
         /* if JPWL is on, we check whether TX errors have damaged
@@ -2211,6 +2228,8 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
 
     l_img_comp = l_image->comps;
 
+    l_prec0 = 0;
+    l_sgnd0 = 0;
     /* Read the component information */
     for (i = 0; i < l_image->numcomps; ++i) {
         OPJ_UINT32 tmp;
@@ -2218,6 +2237,20 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
         ++p_header_data;
         l_img_comp->prec = (tmp & 0x7f) + 1;
         l_img_comp->sgnd = tmp >> 7;
+
+        if (p_j2k->dump_state == 0) {
+            if (i == 0) {
+                l_prec0 = l_img_comp->prec;
+                l_sgnd0 = l_img_comp->sgnd;
+            } else if (!l_cp->allow_different_bit_depth_sign
+                       && (l_img_comp->prec != l_prec0 || l_img_comp->sgnd != l_sgnd0)) {
+                opj_event_msg(p_manager, EVT_WARNING,
+                              "Despite JP2 BPC!=255, precision and/or sgnd values for comp[%d] is different than comp[0]:\n"
+                              "        [0] prec(%d) sgnd(%d) [%d] prec(%d) sgnd(%d)\n", i, l_prec0, l_sgnd0,
+                              i, l_img_comp->prec, l_img_comp->sgnd);
+            }
+            /* TODO: we should perhaps also check against JP2 BPCC values */
+        }
         opj_read_bytes(p_header_data, &tmp, 1); /* XRsiz_i */
         ++p_header_data;
         l_img_comp->dx = (OPJ_UINT32)tmp; /* should be between 1 and 255 */
@@ -2240,7 +2273,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                           i, l_img_comp->prec);
             return OPJ_FALSE;
         }
-
 #ifdef USE_JPWL
         if (l_cp->correct) {
             /* if JPWL is on, we check whether TX errors have damaged
@@ -2277,6 +2309,10 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
         ++l_img_comp;
     }
 
+    if (l_cp->tdx == 0 || l_cp->tdy == 0) {
+        return OPJ_FALSE;
+    }
+
     /* Compute the number of tiles */
     l_cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(l_image->x1 - l_cp->tx0),
                                            (OPJ_INT32)l_cp->tdx);
@@ -4168,6 +4204,7 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k,
 
 static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
                                   OPJ_BYTE * p_data,
+                                  OPJ_UINT32 p_total_data_size,
                                   OPJ_UINT32 * p_data_written,
                                   const opj_stream_private_t *p_stream,
                                   opj_event_mgr_t * p_manager
@@ -4179,7 +4216,12 @@ static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
     assert(p_stream != 00);
 
     OPJ_UNUSED(p_stream);
-    OPJ_UNUSED(p_manager);
+
+    if (p_total_data_size < 12) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "Not enough bytes in output buffer to write SOT marker\n");
+        return OPJ_FALSE;
+    }
 
     opj_write_bytes(p_data, J2K_MS_SOT,
                     2);                                 /* SOT */
@@ -4378,6 +4420,16 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k,
         p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
     }
 
+    if (l_tcp->m_nb_tile_parts != 0 && l_current_part >= l_tcp->m_nb_tile_parts) {
+        /* Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2851 */
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "In SOT marker, TPSot (%d) is not valid regards to the previous "
+                      "number of tile-part (%d), giving up\n", l_current_part,
+                      l_tcp->m_nb_tile_parts);
+        p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
+        return OPJ_FALSE;
+    }
+
     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;
@@ -4565,6 +4617,12 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k,
 
     OPJ_UNUSED(p_stream);
 
+    if (p_total_data_size < 4) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "Not enough bytes in output buffer to write SOD marker\n");
+        return OPJ_FALSE;
+    }
+
     opj_write_bytes(p_data, J2K_MS_SOD,
                     2);                                 /* SOD */
     p_data += 2;
@@ -4616,7 +4674,8 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k,
     *p_data_written = 0;
 
     if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data,
-                              p_data_written, l_remaining_data, l_cstr_info)) {
+                              p_data_written, l_remaining_data, l_cstr_info,
+                              p_manager)) {
         opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n");
         return OPJ_FALSE;
     }
@@ -4674,15 +4733,35 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k,
                           "Tile part length size inconsistent with stream length\n");
             return OPJ_FALSE;
         }
+        if (p_j2k->m_specific_param.m_decoder.m_sot_length >
+                UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA) {
+            opj_event_msg(p_manager, EVT_ERROR,
+                          "p_j2k->m_specific_param.m_decoder.m_sot_length > "
+                          "UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA");
+            return OPJ_FALSE;
+        }
+        /* Add a margin of OPJ_COMMON_CBLK_DATA_EXTRA to the allocation we */
+        /* do so that opj_mqc_init_dec_common() can safely add a synthetic */
+        /* 0xFFFF marker. */
         if (! *l_current_data) {
             /* LH: oddly enough, in this path, l_tile_len!=0.
              * TODO: If this was consistent, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...).
              */
             *l_current_data = (OPJ_BYTE*) opj_malloc(
-                                  p_j2k->m_specific_param.m_decoder.m_sot_length);
+                                  p_j2k->m_specific_param.m_decoder.m_sot_length + OPJ_COMMON_CBLK_DATA_EXTRA);
         } else {
-            OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(*l_current_data,
-                                           *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length);
+            OPJ_BYTE *l_new_current_data;
+            if (*l_tile_len > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA -
+                    p_j2k->m_specific_param.m_decoder.m_sot_length) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                              "*l_tile_len > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA - "
+                              "p_j2k->m_specific_param.m_decoder.m_sot_length");
+                return OPJ_FALSE;
+            }
+
+            l_new_current_data = (OPJ_BYTE *) opj_realloc(*l_current_data,
+                                 *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length +
+                                 OPJ_COMMON_CBLK_DATA_EXTRA);
             if (! l_new_current_data) {
                 opj_free(*l_current_data);
                 /*nothing more is done as l_current_data will be set to null, and just
@@ -5084,7 +5163,17 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
         ++l_img_comp;
     }
 
-    l_tile_size = (OPJ_UINT32)(l_tile_size * 0.1625);  /* 1.3/8 = 0.1625 */
+    /* TODO: where does this magic value come from ? */
+    /* This used to be 1.3 / 8, but with random data and very small code */
+    /* block sizes, this is not enough. For example with */
+    /* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */
+    /* TODO revise this to take into account the overhead linked to the */
+    /* number of packets and number of code blocks in packets */
+    l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8);
+
+    /* Arbitrary amount to make the following work: */
+    /* bin/test_tile_encoder 1 256 256 17 16 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1 */
+    l_tile_size += 500;
 
     l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k);
 
@@ -6315,6 +6404,7 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters)
         j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer;
         j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce;
 
+        j2k->dump_state = (parameters->flags & OPJ_DPARAMETERS_DUMP_FLAG);
 #ifdef USE_JPWL
         j2k->m_cp.correct = parameters->jpwl_correct;
         j2k->m_cp.exp_comps = parameters->jpwl_exp_comps;
@@ -6508,10 +6598,16 @@ static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters,
 
     /* Precincts */
     parameters->csty |= 0x01;
-    parameters->res_spec = parameters->numresolution - 1;
-    for (i = 0; i < parameters->res_spec; i++) {
-        parameters->prcw_init[i] = 256;
-        parameters->prch_init[i] = 256;
+    if (parameters->numresolution == 1) {
+        parameters->res_spec = 1;
+        parameters->prcw_init[0] = 128;
+        parameters->prch_init[0] = 128;
+    } else {
+        parameters->res_spec = parameters->numresolution - 1;
+        for (i = 0; i < parameters->res_spec; i++) {
+            parameters->prcw_init[i] = 256;
+            parameters->prch_init[i] = 256;
+        }
     }
 
     /* The progression order shall be CPRL */
@@ -6705,6 +6801,13 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
         }
     }
 
+    /* If no explicit layers are provided, use lossless settings */
+    if (parameters->tcp_numlayers == 0) {
+        parameters->tcp_numlayers = 1;
+        parameters->cp_disto_alloc = 1;
+        parameters->tcp_rates[0] = 0;
+    }
+
     /* see if max_codestream_size does limit input rate */
     if (parameters->max_cs_size <= 0) {
         if (parameters->tcp_rates[parameters->tcp_numlayers - 1] > 0) {
@@ -8678,6 +8781,7 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
     OPJ_UINT32 l_current_marker;
     OPJ_BYTE l_data [2];
     opj_tcp_t * l_tcp;
+    opj_image_t* l_image_for_bounds;
 
     /* preconditions */
     assert(p_stream != 00);
@@ -8695,7 +8799,18 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
         return OPJ_FALSE;
     }
 
+    /* When using the opj_read_tile_header / opj_decode_tile_data API */
+    /* such as in test_tile_decoder, m_output_image is NULL, so fall back */
+    /* to the full image dimension. This is a bit surprising that */
+    /* opj_set_decode_area() is only used to determinte intersecting tiles, */
+    /* but full tile decoding is done */
+    l_image_for_bounds = p_j2k->m_output_image ? p_j2k->m_output_image :
+                         p_j2k->m_private_image;
     if (! opj_tcd_decode_tile(p_j2k->m_tcd,
+                              l_image_for_bounds->x0,
+                              l_image_for_bounds->y0,
+                              l_image_for_bounds->x1,
+                              l_image_for_bounds->y1,
                               l_tcp->m_data,
                               l_tcp->m_data_size,
                               p_tile_index,
@@ -8706,15 +8821,20 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
         return OPJ_FALSE;
     }
 
-    if (! opj_tcd_update_tile_data(p_j2k->m_tcd, p_data, p_data_size)) {
-        return OPJ_FALSE;
-    }
+    /* p_data can be set to NULL when the call will take care of using */
+    /* itself the TCD data. This is typically the case for whole single */
+    /* tile decoding optimization. */
+    if (p_data != NULL) {
+        if (! opj_tcd_update_tile_data(p_j2k->m_tcd, p_data, p_data_size)) {
+            return OPJ_FALSE;
+        }
 
-    /* To avoid to destroy the tcp which can be useful when we try to decode a tile decoded before (cf j2k_random_tile_access)
-     * we destroy just the data which will be re-read in read_tile_header*/
-    /*opj_j2k_tcp_destroy(l_tcp);
-    p_j2k->m_tcd->tcp = 0;*/
-    opj_j2k_tcp_data_destroy(l_tcp);
+        /* To avoid to destroy the tcp which can be useful when we try to decode a tile decoded before (cf j2k_random_tile_access)
+        * we destroy just the data which will be re-read in read_tile_header*/
+        /*opj_j2k_tcp_destroy(l_tcp);
+        p_j2k->m_tcd->tcp = 0;*/
+        opj_j2k_tcp_data_destroy(l_tcp);
+    }
 
     p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
     p_j2k->m_specific_param.m_decoder.m_state &= (~(OPJ_UINT32)J2K_STATE_DATA);
@@ -8783,15 +8903,18 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
             OPJ_SIZE_T l_width = l_img_comp_dest->w;
             OPJ_SIZE_T l_height = l_img_comp_dest->h;
 
-            if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height))) {
+            if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height)) ||
+                    l_width * l_height > SIZE_MAX / sizeof(OPJ_INT32)) {
                 /* would overflow */
                 return OPJ_FALSE;
             }
-            l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_width * l_height,
+            l_img_comp_dest->data = (OPJ_INT32*) opj_image_data_alloc(l_width * l_height *
                                     sizeof(OPJ_INT32));
             if (! l_img_comp_dest->data) {
                 return OPJ_FALSE;
             }
+            /* Do we really need this memset ? */
+            memset(l_img_comp_dest->data, 0, l_width * l_height * sizeof(OPJ_INT32));
         }
 
         /* Copy info from decoded comp image to output image */
@@ -9200,6 +9323,9 @@ opj_j2k_t* opj_j2k_create_decompress(void)
 
     l_j2k->m_is_decoder = 1;
     l_j2k->m_cp.m_is_decoder = 1;
+    /* in the absence of JP2 boxes, consider different bit depth / sign */
+    /* per component is allowed */
+    l_j2k->m_cp.allow_different_bit_depth_sign = 1;
 
 #ifdef OPJ_DISABLE_TPSOT_FIX
     l_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1;
@@ -10371,6 +10497,47 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
     OPJ_BYTE * l_current_data;
     OPJ_UINT32 nr_tiles = 0;
 
+    /* Particular case for whole single tile decoding */
+    /* We can avoid allocating intermediate tile buffers */
+    if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
+            p_j2k->m_cp.tx0 == 0 && p_j2k->m_cp.ty0 == 0 &&
+            p_j2k->m_output_image->x0 == 0 &&
+            p_j2k->m_output_image->y0 == 0 &&
+            p_j2k->m_output_image->x1 == p_j2k->m_cp.tdx &&
+            p_j2k->m_output_image->y1 == p_j2k->m_cp.tdy &&
+            p_j2k->m_output_image->comps[0].factor == 0) {
+        OPJ_UINT32 i;
+        if (! opj_j2k_read_tile_header(p_j2k,
+                                       &l_current_tile_no,
+                                       &l_data_size,
+                                       &l_tile_x0, &l_tile_y0,
+                                       &l_tile_x1, &l_tile_y1,
+                                       &l_nb_comps,
+                                       &l_go_on,
+                                       p_stream,
+                                       p_manager)) {
+            return OPJ_FALSE;
+        }
+
+        if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
+                                  p_stream, p_manager)) {
+            opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile 1/1\n");
+            return OPJ_FALSE;
+        }
+
+        /* Transfer TCD data to output image data */
+        for (i = 0; i < p_j2k->m_output_image->numcomps; i++) {
+            opj_image_data_free(p_j2k->m_output_image->comps[i].data);
+            p_j2k->m_output_image->comps[i].data =
+                p_j2k->m_tcd->tcd_image->tiles->comps[i].data;
+            p_j2k->m_output_image->comps[i].resno_decoded =
+                p_j2k->m_tcd->image->comps[i].resno_decoded;
+            p_j2k->m_tcd->tcd_image->tiles->comps[i].data = NULL;
+        }
+
+        return OPJ_TRUE;
+    }
+
     l_current_data = (OPJ_BYTE*)opj_malloc(1000);
     if (! l_current_data) {
         opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n");
@@ -10636,7 +10803,9 @@ 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, p_manager);
+    if (!opj_j2k_setup_decoding(p_j2k, p_manager)) {
+        return OPJ_FALSE;
+    }
 
     /* Decode the codestream */
     if (! opj_j2k_exec(p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) {
@@ -10746,7 +10915,9 @@ 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, p_manager);
+    if (!opj_j2k_setup_decoding_tile(p_j2k, p_manager)) {
+        return OPJ_FALSE;
+    }
 
     /* Decode the codestream */
     if (! opj_j2k_exec(p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) {
@@ -10761,7 +10932,7 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k,
             p_j2k->m_output_image->comps[compno].resno_decoded;
 
         if (p_image->comps[compno].data) {
-            opj_free(p_image->comps[compno].data);
+            opj_image_data_free(p_image->comps[compno].data);
         }
 
         p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
@@ -11346,7 +11517,8 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k,
 
     l_current_nb_bytes_written = 0;
     l_begin_data = p_data;
-    if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream,
+    if (! opj_j2k_write_sot(p_j2k, p_data, p_total_data_size,
+                            &l_current_nb_bytes_written, p_stream,
                             p_manager)) {
         return OPJ_FALSE;
     }
@@ -11438,7 +11610,10 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k,
         l_part_tile_size = 0;
         l_begin_data = p_data;
 
-        if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream,
+        if (! opj_j2k_write_sot(p_j2k, p_data,
+                                p_total_data_size,
+                                &l_current_nb_bytes_written,
+                                p_stream,
                                 p_manager)) {
             return OPJ_FALSE;
         }
@@ -11481,7 +11656,9 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k,
             l_part_tile_size = 0;
             l_begin_data = p_data;
 
-            if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream,
+            if (! opj_j2k_write_sot(p_j2k, p_data,
+                                    p_total_data_size,
+                                    &l_current_nb_bytes_written, p_stream,
                                     p_manager)) {
                 return OPJ_FALSE;
             }