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