Home | History | Annotate | Download | only in libopenjpeg20
      1 /*
      2  * The copyright in this software is being made available under the 2-clauses
      3  * BSD License, included below. This software may be subject to other third
      4  * party and contributor rights, including patent rights, and no such rights
      5  * are granted under this license.
      6  *
      7  * Copyright (c) 2017, IntoPix SA <contact (at) intopix.com>
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
     20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "opj_includes.h"
     33 
     34 
     35 struct opj_sparse_array_int32 {
     36     OPJ_UINT32 width;
     37     OPJ_UINT32 height;
     38     OPJ_UINT32 block_width;
     39     OPJ_UINT32 block_height;
     40     OPJ_UINT32 block_count_hor;
     41     OPJ_UINT32 block_count_ver;
     42     OPJ_INT32** data_blocks;
     43 };
     44 
     45 opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width,
     46         OPJ_UINT32 height,
     47         OPJ_UINT32 block_width,
     48         OPJ_UINT32 block_height)
     49 {
     50     opj_sparse_array_int32_t* sa;
     51 
     52     if (width == 0 || height == 0 || block_width == 0 || block_height == 0) {
     53         return NULL;
     54     }
     55     if (block_width > ((OPJ_UINT32)~0U) / block_height / sizeof(OPJ_INT32)) {
     56         return NULL;
     57     }
     58 
     59     sa = (opj_sparse_array_int32_t*) opj_calloc(1,
     60             sizeof(opj_sparse_array_int32_t));
     61     sa->width = width;
     62     sa->height = height;
     63     sa->block_width = block_width;
     64     sa->block_height = block_height;
     65     sa->block_count_hor = opj_uint_ceildiv(width, block_width);
     66     sa->block_count_ver = opj_uint_ceildiv(height, block_height);
     67     if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) {
     68         opj_free(sa);
     69         return NULL;
     70     }
     71     sa->data_blocks = (OPJ_INT32**) opj_calloc(sizeof(OPJ_INT32*),
     72                       sa->block_count_hor * sa->block_count_ver);
     73     if (sa->data_blocks == NULL) {
     74         opj_free(sa);
     75         return NULL;
     76     }
     77 
     78     return sa;
     79 }
     80 
     81 void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa)
     82 {
     83     if (sa) {
     84         OPJ_UINT32 i;
     85         for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) {
     86             if (sa->data_blocks[i]) {
     87                 opj_free(sa->data_blocks[i]);
     88             }
     89         }
     90         opj_free(sa->data_blocks);
     91         opj_free(sa);
     92     }
     93 }
     94 
     95 OPJ_BOOL opj_sparse_array_is_region_valid(const opj_sparse_array_int32_t* sa,
     96         OPJ_UINT32 x0,
     97         OPJ_UINT32 y0,
     98         OPJ_UINT32 x1,
     99         OPJ_UINT32 y1)
    100 {
    101     return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width ||
    102              y0 >= sa->height || y1 <= y0 || y1 > sa->height);
    103 }
    104 
    105 static OPJ_BOOL opj_sparse_array_int32_read_or_write(
    106     const opj_sparse_array_int32_t* sa,
    107     OPJ_UINT32 x0,
    108     OPJ_UINT32 y0,
    109     OPJ_UINT32 x1,
    110     OPJ_UINT32 y1,
    111     OPJ_INT32* buf,
    112     OPJ_UINT32 buf_col_stride,
    113     OPJ_UINT32 buf_line_stride,
    114     OPJ_BOOL forgiving,
    115     OPJ_BOOL is_read_op)
    116 {
    117     OPJ_UINT32 y, block_y;
    118     OPJ_UINT32 y_incr = 0;
    119     const OPJ_UINT32 block_width = sa->block_width;
    120 
    121     if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) {
    122         return forgiving;
    123     }
    124 
    125     block_y = y0 / sa->block_height;
    126     for (y = y0; y < y1; block_y ++, y += y_incr) {
    127         OPJ_UINT32 x, block_x;
    128         OPJ_UINT32 x_incr = 0;
    129         OPJ_UINT32 block_y_offset;
    130         y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) :
    131                  sa->block_height;
    132         block_y_offset = sa->block_height - y_incr;
    133         y_incr = opj_uint_min(y_incr, y1 - y);
    134         block_x = x0 / block_width;
    135         for (x = x0; x < x1; block_x ++, x += x_incr) {
    136             OPJ_UINT32 j;
    137             OPJ_UINT32 block_x_offset;
    138             OPJ_INT32* src_block;
    139             x_incr = (x == x0) ? block_width - (x0 % block_width) : block_width;
    140             block_x_offset = block_width - x_incr;
    141             x_incr = opj_uint_min(x_incr, x1 - x);
    142             src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x];
    143             if (is_read_op) {
    144                 if (src_block == NULL) {
    145                     if (buf_col_stride == 1) {
    146                         OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride +
    147                                               (x - x0) * buf_col_stride;
    148                         for (j = 0; j < y_incr; j++) {
    149                             memset(dest_ptr, 0, sizeof(OPJ_INT32) * x_incr);
    150                             dest_ptr += buf_line_stride;
    151                         }
    152                     } else {
    153                         OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride +
    154                                               (x - x0) * buf_col_stride;
    155                         for (j = 0; j < y_incr; j++) {
    156                             OPJ_UINT32 k;
    157                             for (k = 0; k < x_incr; k++) {
    158                                 dest_ptr[k * buf_col_stride] = 0;
    159                             }
    160                             dest_ptr += buf_line_stride;
    161                         }
    162                     }
    163                 } else {
    164                     const OPJ_INT32* OPJ_RESTRICT src_ptr = src_block + block_y_offset *
    165                                                             (OPJ_SIZE_T)block_width + block_x_offset;
    166                     if (buf_col_stride == 1) {
    167                         OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride
    168                                                            +
    169                                                            (x - x0) * buf_col_stride;
    170                         if (x_incr == 4) {
    171                             /* Same code as general branch, but the compiler */
    172                             /* can have an efficient memcpy() */
    173                             (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */
    174                             for (j = 0; j < y_incr; j++) {
    175                                 memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
    176                                 dest_ptr += buf_line_stride;
    177                                 src_ptr += block_width;
    178                             }
    179                         } else {
    180                             for (j = 0; j < y_incr; j++) {
    181                                 memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
    182                                 dest_ptr += buf_line_stride;
    183                                 src_ptr += block_width;
    184                             }
    185                         }
    186                     } else {
    187                         OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride
    188                                                            +
    189                                                            (x - x0) * buf_col_stride;
    190                         if (x_incr == 1) {
    191                             for (j = 0; j < y_incr; j++) {
    192                                 *dest_ptr = *src_ptr;
    193                                 dest_ptr += buf_line_stride;
    194                                 src_ptr += block_width;
    195                             }
    196                         } else if (y_incr == 1 && buf_col_stride == 2) {
    197                             OPJ_UINT32 k;
    198                             for (k = 0; k < (x_incr & ~3U); k += 4) {
    199                                 dest_ptr[k * buf_col_stride] = src_ptr[k];
    200                                 dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1];
    201                                 dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2];
    202                                 dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3];
    203                             }
    204                             for (; k < x_incr; k++) {
    205                                 dest_ptr[k * buf_col_stride] = src_ptr[k];
    206                             }
    207                         } else if (x_incr >= 8 && buf_col_stride == 8) {
    208                             for (j = 0; j < y_incr; j++) {
    209                                 OPJ_UINT32 k;
    210                                 for (k = 0; k < (x_incr & ~3U); k += 4) {
    211                                     dest_ptr[k * buf_col_stride] = src_ptr[k];
    212                                     dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1];
    213                                     dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2];
    214                                     dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3];
    215                                 }
    216                                 for (; k < x_incr; k++) {
    217                                     dest_ptr[k * buf_col_stride] = src_ptr[k];
    218                                 }
    219                                 dest_ptr += buf_line_stride;
    220                                 src_ptr += block_width;
    221                             }
    222                         } else {
    223                             /* General case */
    224                             for (j = 0; j < y_incr; j++) {
    225                                 OPJ_UINT32 k;
    226                                 for (k = 0; k < x_incr; k++) {
    227                                     dest_ptr[k * buf_col_stride] = src_ptr[k];
    228                                 }
    229                                 dest_ptr += buf_line_stride;
    230                                 src_ptr += block_width;
    231                             }
    232                         }
    233                     }
    234                 }
    235             } else {
    236                 if (src_block == NULL) {
    237                     src_block = (OPJ_INT32*) opj_calloc(1,
    238                                                         sa->block_width * sa->block_height * sizeof(OPJ_INT32));
    239                     if (src_block == NULL) {
    240                         return OPJ_FALSE;
    241                     }
    242                     sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block;
    243                 }
    244 
    245                 if (buf_col_stride == 1) {
    246                     OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset *
    247                                                        (OPJ_SIZE_T)block_width + block_x_offset;
    248                     const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) *
    249                                                             (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride;
    250                     if (x_incr == 4) {
    251                         /* Same code as general branch, but the compiler */
    252                         /* can have an efficient memcpy() */
    253                         (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */
    254                         for (j = 0; j < y_incr; j++) {
    255                             memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
    256                             dest_ptr += block_width;
    257                             src_ptr += buf_line_stride;
    258                         }
    259                     } else {
    260                         for (j = 0; j < y_incr; j++) {
    261                             memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
    262                             dest_ptr += block_width;
    263                             src_ptr += buf_line_stride;
    264                         }
    265                     }
    266                 } else {
    267                     OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset *
    268                                                        (OPJ_SIZE_T)block_width + block_x_offset;
    269                     const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) *
    270                                                             (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride;
    271                     if (x_incr == 1) {
    272                         for (j = 0; j < y_incr; j++) {
    273                             *dest_ptr = *src_ptr;
    274                             src_ptr += buf_line_stride;
    275                             dest_ptr += block_width;
    276                         }
    277                     } else if (x_incr >= 8 && buf_col_stride == 8) {
    278                         for (j = 0; j < y_incr; j++) {
    279                             OPJ_UINT32 k;
    280                             for (k = 0; k < (x_incr & ~3U); k += 4) {
    281                                 dest_ptr[k] = src_ptr[k * buf_col_stride];
    282                                 dest_ptr[k + 1] = src_ptr[(k + 1) * buf_col_stride];
    283                                 dest_ptr[k + 2] = src_ptr[(k + 2) * buf_col_stride];
    284                                 dest_ptr[k + 3] = src_ptr[(k + 3) * buf_col_stride];
    285                             }
    286                             for (; k < x_incr; k++) {
    287                                 dest_ptr[k] = src_ptr[k * buf_col_stride];
    288                             }
    289                             src_ptr += buf_line_stride;
    290                             dest_ptr += block_width;
    291                         }
    292                     } else {
    293                         /* General case */
    294                         for (j = 0; j < y_incr; j++) {
    295                             OPJ_UINT32 k;
    296                             for (k = 0; k < x_incr; k++) {
    297                                 dest_ptr[k] = src_ptr[k * buf_col_stride];
    298                             }
    299                             src_ptr += buf_line_stride;
    300                             dest_ptr += block_width;
    301                         }
    302                     }
    303                 }
    304             }
    305         }
    306     }
    307 
    308     return OPJ_TRUE;
    309 }
    310 
    311 OPJ_BOOL opj_sparse_array_int32_read(const opj_sparse_array_int32_t* sa,
    312                                      OPJ_UINT32 x0,
    313                                      OPJ_UINT32 y0,
    314                                      OPJ_UINT32 x1,
    315                                      OPJ_UINT32 y1,
    316                                      OPJ_INT32* dest,
    317                                      OPJ_UINT32 dest_col_stride,
    318                                      OPJ_UINT32 dest_line_stride,
    319                                      OPJ_BOOL forgiving)
    320 {
    321     return opj_sparse_array_int32_read_or_write(
    322                (opj_sparse_array_int32_t*)sa, x0, y0, x1, y1,
    323                dest,
    324                dest_col_stride,
    325                dest_line_stride,
    326                forgiving,
    327                OPJ_TRUE);
    328 }
    329 
    330 OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa,
    331                                       OPJ_UINT32 x0,
    332                                       OPJ_UINT32 y0,
    333                                       OPJ_UINT32 x1,
    334                                       OPJ_UINT32 y1,
    335                                       const OPJ_INT32* src,
    336                                       OPJ_UINT32 src_col_stride,
    337                                       OPJ_UINT32 src_line_stride,
    338                                       OPJ_BOOL forgiving)
    339 {
    340     return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
    341             (OPJ_INT32*)src,
    342             src_col_stride,
    343             src_line_stride,
    344             forgiving,
    345             OPJ_FALSE);
    346 }
    347