| /* | 
 |  * The copyright in this software is being made available under the 2-clauses | 
 |  * BSD License, included below. This software may be subject to other third | 
 |  * party and contributor rights, including patent rights, and no such rights | 
 |  * are granted under this license. | 
 |  * | 
 |  * Copyright (c) 2017, IntoPix SA <contact@intopix.com> | 
 |  * All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' | 
 |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
 |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 
 |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
 |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
 |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
 |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
 |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
 |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
 |  * POSSIBILITY OF SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | #include "opj_includes.h" | 
 |  | 
 |  | 
 | struct opj_sparse_array_int32 { | 
 |     OPJ_UINT32 width; | 
 |     OPJ_UINT32 height; | 
 |     OPJ_UINT32 block_width; | 
 |     OPJ_UINT32 block_height; | 
 |     OPJ_UINT32 block_count_hor; | 
 |     OPJ_UINT32 block_count_ver; | 
 |     OPJ_INT32** data_blocks; | 
 | }; | 
 |  | 
 | opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width, | 
 |         OPJ_UINT32 height, | 
 |         OPJ_UINT32 block_width, | 
 |         OPJ_UINT32 block_height) | 
 | { | 
 |     opj_sparse_array_int32_t* sa; | 
 |  | 
 |     if (width == 0 || height == 0 || block_width == 0 || block_height == 0) { | 
 |         return NULL; | 
 |     } | 
 |     if (block_width > ((OPJ_UINT32)~0U) / block_height / sizeof(OPJ_INT32)) { | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     sa = (opj_sparse_array_int32_t*) opj_calloc(1, | 
 |             sizeof(opj_sparse_array_int32_t)); | 
 |     sa->width = width; | 
 |     sa->height = height; | 
 |     sa->block_width = block_width; | 
 |     sa->block_height = block_height; | 
 |     sa->block_count_hor = opj_uint_ceildiv(width, block_width); | 
 |     sa->block_count_ver = opj_uint_ceildiv(height, block_height); | 
 |     if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) { | 
 |         opj_free(sa); | 
 |         return NULL; | 
 |     } | 
 |     sa->data_blocks = (OPJ_INT32**) opj_calloc(sizeof(OPJ_INT32*), | 
 |                       (size_t) sa->block_count_hor * sa->block_count_ver); | 
 |     if (sa->data_blocks == NULL) { | 
 |         opj_free(sa); | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     return sa; | 
 | } | 
 |  | 
 | void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa) | 
 | { | 
 |     if (sa) { | 
 |         OPJ_UINT32 i; | 
 |         for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) { | 
 |             if (sa->data_blocks[i]) { | 
 |                 opj_free(sa->data_blocks[i]); | 
 |             } | 
 |         } | 
 |         opj_free(sa->data_blocks); | 
 |         opj_free(sa); | 
 |     } | 
 | } | 
 |  | 
 | OPJ_BOOL opj_sparse_array_is_region_valid(const opj_sparse_array_int32_t* sa, | 
 |         OPJ_UINT32 x0, | 
 |         OPJ_UINT32 y0, | 
 |         OPJ_UINT32 x1, | 
 |         OPJ_UINT32 y1) | 
 | { | 
 |     return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width || | 
 |              y0 >= sa->height || y1 <= y0 || y1 > sa->height); | 
 | } | 
 |  | 
 | static OPJ_BOOL opj_sparse_array_int32_read_or_write( | 
 |     const opj_sparse_array_int32_t* sa, | 
 |     OPJ_UINT32 x0, | 
 |     OPJ_UINT32 y0, | 
 |     OPJ_UINT32 x1, | 
 |     OPJ_UINT32 y1, | 
 |     OPJ_INT32* buf, | 
 |     OPJ_UINT32 buf_col_stride, | 
 |     OPJ_UINT32 buf_line_stride, | 
 |     OPJ_BOOL forgiving, | 
 |     OPJ_BOOL is_read_op) | 
 | { | 
 |     OPJ_UINT32 y, block_y; | 
 |     OPJ_UINT32 y_incr = 0; | 
 |     const OPJ_UINT32 block_width = sa->block_width; | 
 |  | 
 |     if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) { | 
 |         return forgiving; | 
 |     } | 
 |  | 
 |     block_y = y0 / sa->block_height; | 
 |     for (y = y0; y < y1; block_y ++, y += y_incr) { | 
 |         OPJ_UINT32 x, block_x; | 
 |         OPJ_UINT32 x_incr = 0; | 
 |         OPJ_UINT32 block_y_offset; | 
 |         y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) : | 
 |                  sa->block_height; | 
 |         block_y_offset = sa->block_height - y_incr; | 
 |         y_incr = opj_uint_min(y_incr, y1 - y); | 
 |         block_x = x0 / block_width; | 
 |         for (x = x0; x < x1; block_x ++, x += x_incr) { | 
 |             OPJ_UINT32 j; | 
 |             OPJ_UINT32 block_x_offset; | 
 |             OPJ_INT32* src_block; | 
 |             x_incr = (x == x0) ? block_width - (x0 % block_width) : block_width; | 
 |             block_x_offset = block_width - x_incr; | 
 |             x_incr = opj_uint_min(x_incr, x1 - x); | 
 |             src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x]; | 
 |             if (is_read_op) { | 
 |                 if (src_block == NULL) { | 
 |                     if (buf_col_stride == 1) { | 
 |                         OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride + | 
 |                                               (x - x0) * buf_col_stride; | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             memset(dest_ptr, 0, sizeof(OPJ_INT32) * x_incr); | 
 |                             dest_ptr += buf_line_stride; | 
 |                         } | 
 |                     } else { | 
 |                         OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride + | 
 |                                               (x - x0) * buf_col_stride; | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             OPJ_UINT32 k; | 
 |                             for (k = 0; k < x_incr; k++) { | 
 |                                 dest_ptr[k * buf_col_stride] = 0; | 
 |                             } | 
 |                             dest_ptr += buf_line_stride; | 
 |                         } | 
 |                     } | 
 |                 } else { | 
 |                     const OPJ_INT32* OPJ_RESTRICT src_ptr = src_block + block_y_offset * | 
 |                                                             (OPJ_SIZE_T)block_width + block_x_offset; | 
 |                     if (buf_col_stride == 1) { | 
 |                         OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride | 
 |                                                            + | 
 |                                                            (x - x0) * buf_col_stride; | 
 |                         if (x_incr == 4) { | 
 |                             /* Same code as general branch, but the compiler */ | 
 |                             /* can have an efficient memcpy() */ | 
 |                             (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */ | 
 |                             for (j = 0; j < y_incr; j++) { | 
 |                                 memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); | 
 |                                 dest_ptr += buf_line_stride; | 
 |                                 src_ptr += block_width; | 
 |                             } | 
 |                         } else { | 
 |                             for (j = 0; j < y_incr; j++) { | 
 |                                 memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); | 
 |                                 dest_ptr += buf_line_stride; | 
 |                                 src_ptr += block_width; | 
 |                             } | 
 |                         } | 
 |                     } else { | 
 |                         OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride | 
 |                                                            + | 
 |                                                            (x - x0) * buf_col_stride; | 
 |                         if (x_incr == 1) { | 
 |                             for (j = 0; j < y_incr; j++) { | 
 |                                 *dest_ptr = *src_ptr; | 
 |                                 dest_ptr += buf_line_stride; | 
 |                                 src_ptr += block_width; | 
 |                             } | 
 |                         } else if (y_incr == 1 && buf_col_stride == 2) { | 
 |                             OPJ_UINT32 k; | 
 |                             for (k = 0; k < (x_incr & ~3U); k += 4) { | 
 |                                 dest_ptr[k * buf_col_stride] = src_ptr[k]; | 
 |                                 dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1]; | 
 |                                 dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2]; | 
 |                                 dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3]; | 
 |                             } | 
 |                             for (; k < x_incr; k++) { | 
 |                                 dest_ptr[k * buf_col_stride] = src_ptr[k]; | 
 |                             } | 
 |                         } else if (x_incr >= 8 && buf_col_stride == 8) { | 
 |                             for (j = 0; j < y_incr; j++) { | 
 |                                 OPJ_UINT32 k; | 
 |                                 for (k = 0; k < (x_incr & ~3U); k += 4) { | 
 |                                     dest_ptr[k * buf_col_stride] = src_ptr[k]; | 
 |                                     dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1]; | 
 |                                     dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2]; | 
 |                                     dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3]; | 
 |                                 } | 
 |                                 for (; k < x_incr; k++) { | 
 |                                     dest_ptr[k * buf_col_stride] = src_ptr[k]; | 
 |                                 } | 
 |                                 dest_ptr += buf_line_stride; | 
 |                                 src_ptr += block_width; | 
 |                             } | 
 |                         } else { | 
 |                             /* General case */ | 
 |                             for (j = 0; j < y_incr; j++) { | 
 |                                 OPJ_UINT32 k; | 
 |                                 for (k = 0; k < x_incr; k++) { | 
 |                                     dest_ptr[k * buf_col_stride] = src_ptr[k]; | 
 |                                 } | 
 |                                 dest_ptr += buf_line_stride; | 
 |                                 src_ptr += block_width; | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } else { | 
 |                 if (src_block == NULL) { | 
 |                     src_block = (OPJ_INT32*) opj_calloc(1, | 
 |                                                         (size_t) sa->block_width * sa->block_height * sizeof(OPJ_INT32)); | 
 |                     if (src_block == NULL) { | 
 |                         return OPJ_FALSE; | 
 |                     } | 
 |                     sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block; | 
 |                 } | 
 |  | 
 |                 if (buf_col_stride == 1) { | 
 |                     OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset * | 
 |                                                        (OPJ_SIZE_T)block_width + block_x_offset; | 
 |                     const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) * | 
 |                                                             (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride; | 
 |                     if (x_incr == 4) { | 
 |                         /* Same code as general branch, but the compiler */ | 
 |                         /* can have an efficient memcpy() */ | 
 |                         (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */ | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); | 
 |                             dest_ptr += block_width; | 
 |                             src_ptr += buf_line_stride; | 
 |                         } | 
 |                     } else { | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); | 
 |                             dest_ptr += block_width; | 
 |                             src_ptr += buf_line_stride; | 
 |                         } | 
 |                     } | 
 |                 } else { | 
 |                     OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset * | 
 |                                                        (OPJ_SIZE_T)block_width + block_x_offset; | 
 |                     const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) * | 
 |                                                             (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride; | 
 |                     if (x_incr == 1) { | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             *dest_ptr = *src_ptr; | 
 |                             src_ptr += buf_line_stride; | 
 |                             dest_ptr += block_width; | 
 |                         } | 
 |                     } else if (x_incr >= 8 && buf_col_stride == 8) { | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             OPJ_UINT32 k; | 
 |                             for (k = 0; k < (x_incr & ~3U); k += 4) { | 
 |                                 dest_ptr[k] = src_ptr[k * buf_col_stride]; | 
 |                                 dest_ptr[k + 1] = src_ptr[(k + 1) * buf_col_stride]; | 
 |                                 dest_ptr[k + 2] = src_ptr[(k + 2) * buf_col_stride]; | 
 |                                 dest_ptr[k + 3] = src_ptr[(k + 3) * buf_col_stride]; | 
 |                             } | 
 |                             for (; k < x_incr; k++) { | 
 |                                 dest_ptr[k] = src_ptr[k * buf_col_stride]; | 
 |                             } | 
 |                             src_ptr += buf_line_stride; | 
 |                             dest_ptr += block_width; | 
 |                         } | 
 |                     } else { | 
 |                         /* General case */ | 
 |                         for (j = 0; j < y_incr; j++) { | 
 |                             OPJ_UINT32 k; | 
 |                             for (k = 0; k < x_incr; k++) { | 
 |                                 dest_ptr[k] = src_ptr[k * buf_col_stride]; | 
 |                             } | 
 |                             src_ptr += buf_line_stride; | 
 |                             dest_ptr += block_width; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     return OPJ_TRUE; | 
 | } | 
 |  | 
 | OPJ_BOOL opj_sparse_array_int32_read(const opj_sparse_array_int32_t* sa, | 
 |                                      OPJ_UINT32 x0, | 
 |                                      OPJ_UINT32 y0, | 
 |                                      OPJ_UINT32 x1, | 
 |                                      OPJ_UINT32 y1, | 
 |                                      OPJ_INT32* dest, | 
 |                                      OPJ_UINT32 dest_col_stride, | 
 |                                      OPJ_UINT32 dest_line_stride, | 
 |                                      OPJ_BOOL forgiving) | 
 | { | 
 |     return opj_sparse_array_int32_read_or_write( | 
 |                (opj_sparse_array_int32_t*)sa, x0, y0, x1, y1, | 
 |                dest, | 
 |                dest_col_stride, | 
 |                dest_line_stride, | 
 |                forgiving, | 
 |                OPJ_TRUE); | 
 | } | 
 |  | 
 | OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa, | 
 |                                       OPJ_UINT32 x0, | 
 |                                       OPJ_UINT32 y0, | 
 |                                       OPJ_UINT32 x1, | 
 |                                       OPJ_UINT32 y1, | 
 |                                       const OPJ_INT32* src, | 
 |                                       OPJ_UINT32 src_col_stride, | 
 |                                       OPJ_UINT32 src_line_stride, | 
 |                                       OPJ_BOOL forgiving) | 
 | { | 
 |     return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1, | 
 |             (OPJ_INT32*)src, | 
 |             src_col_stride, | 
 |             src_line_stride, | 
 |             forgiving, | 
 |             OPJ_FALSE); | 
 | } |