3402dca2d18c00bfb8a6c89db4fd49c5453320e7
[openjpeg.git] / src / lib / openjp2 / sparse_array.c
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@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_calloc(1, sizeof(opj_sparse_array_int32_t));
60     sa->width = width;
61     sa->height = height;
62     sa->block_width = block_width;
63     sa->block_height = block_height;
64     sa->block_count_hor = opj_uint_ceildiv(width, block_width);
65     sa->block_count_ver = opj_uint_ceildiv(height, block_height);
66     if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) {
67         opj_free(sa);
68         return NULL;
69     }
70     sa->data_blocks = opj_calloc(sizeof(OPJ_INT32*),
71                                  sa->block_count_hor * sa->block_count_ver);
72     if (sa->data_blocks == NULL) {
73         opj_free(sa);
74         return NULL;
75     }
76
77     return sa;
78 }
79
80 void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa)
81 {
82     if (sa) {
83         OPJ_UINT32 i;
84         for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) {
85             if (sa->data_blocks[i]) {
86                 opj_free(sa->data_blocks[i]);
87             }
88         }
89         opj_free(sa->data_blocks);
90         opj_free(sa);
91     }
92 }
93
94 OPJ_BOOL opj_sparse_array_is_region_valid(opj_sparse_array_int32_t* sa,
95         OPJ_UINT32 x0,
96         OPJ_UINT32 y0,
97         OPJ_UINT32 x1,
98         OPJ_UINT32 y1)
99 {
100     return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width ||
101              y0 >= sa->height || y1 <= y0 || y1 > sa->height);
102 }
103
104 static OPJ_BOOL opj_sparse_array_int32_read_or_write(
105     opj_sparse_array_int32_t* sa,
106     OPJ_UINT32 x0,
107     OPJ_UINT32 y0,
108     OPJ_UINT32 x1,
109     OPJ_UINT32 y1,
110     OPJ_INT32* buf,
111     OPJ_UINT32 buf_col_stride,
112     OPJ_UINT32 buf_line_stride,
113     OPJ_BOOL forgiving,
114     OPJ_BOOL is_read_op)
115 {
116     OPJ_UINT32 y, block_y;
117     OPJ_UINT32 y_incr = 0;
118     if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) {
119         return forgiving;
120     }
121
122     block_y = y0 / sa->block_height;
123     for (y = y0; y < y1; block_y ++, y += y_incr) {
124         OPJ_UINT32 x, block_x;
125         OPJ_UINT32 x_incr = 0;
126         OPJ_UINT32 block_y_offset;
127         y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) :
128                  sa->block_height;
129         block_y_offset = sa->block_height - y_incr;
130         y_incr = opj_uint_min(y_incr, y1 - y);
131         block_x = x0 / sa->block_width;
132         for (x = x0; x < x1; block_x ++, x += x_incr) {
133             OPJ_UINT32 j;
134             OPJ_UINT32 block_x_offset;
135             OPJ_INT32* src_block;
136             x_incr = (x == x0) ? sa->block_width - (x0 % sa->block_width) : sa->block_width;
137             block_x_offset = sa->block_width - x_incr;
138             x_incr = opj_uint_min(x_incr, x1 - x);
139             src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x];
140             if (is_read_op) {
141                 if (src_block == NULL) {
142                     for (j = 0; j < y_incr; j++) {
143                         if (buf_col_stride == 1) {
144                             memset(buf + (y - y0 + j) * (size_t)buf_line_stride + (x - x0) * buf_col_stride,
145                                    0,
146                                    sizeof(OPJ_INT32) * x_incr);
147                         } else {
148                             OPJ_UINT32 k;
149                             for (k = 0; k < x_incr; k++) {
150                                 *(buf + (y - y0 + j) * (size_t)buf_line_stride + (x - x0 + k) * buf_col_stride)
151                                     = 0;
152                             }
153                         }
154                     }
155                 } else {
156                     for (j = 0; j < y_incr; j++) {
157                         if (buf_col_stride == 1) {
158                             memcpy(buf + (y - y0 + j) * (size_t)buf_line_stride + (x - x0) * buf_col_stride,
159                                    src_block + (block_y_offset + j) * (size_t)sa->block_width + block_x_offset,
160                                    sizeof(OPJ_INT32) * x_incr);
161                         } else {
162                             OPJ_UINT32 k;
163                             for (k = 0; k < x_incr; k++) {
164                                 *(buf + (y - y0 + j) * (size_t)buf_line_stride + (x - x0 + k) * buf_col_stride)
165                                     =
166                                         *(src_block + (block_y_offset + j) * (size_t)sa->block_width + block_x_offset +
167                                           k);
168                             }
169                         }
170                     }
171                 }
172             } else {
173                 if (src_block == NULL) {
174                     src_block = opj_calloc(1,
175                                            sa->block_width * sa->block_height * sizeof(OPJ_INT32));
176                     if (src_block == NULL) {
177                         return OPJ_FALSE;
178                     }
179                     sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block;
180                 }
181
182                 for (j = 0; j < y_incr; j++) {
183                     if (buf_col_stride == 1) {
184                         memcpy(src_block + (block_y_offset + j) * (size_t)sa->block_width +
185                                block_x_offset,
186                                buf + (y - y0 + j) * (size_t)buf_line_stride + (x - x0) * buf_col_stride,
187                                sizeof(OPJ_INT32) * x_incr);
188                     } else {
189                         OPJ_UINT32 k;
190                         for (k = 0; k < x_incr; k++) {
191                             *(src_block + (block_y_offset + j) * (size_t)sa->block_width + block_x_offset +
192                               k) =
193                                   *(buf + (y - y0 + j) * (size_t)buf_line_stride + (x - x0 + k) * buf_col_stride);
194                         }
195                     }
196                 }
197             }
198         }
199     }
200
201     return OPJ_TRUE;
202 }
203
204 OPJ_BOOL opj_sparse_array_int32_read(opj_sparse_array_int32_t* sa,
205                                      OPJ_UINT32 x0,
206                                      OPJ_UINT32 y0,
207                                      OPJ_UINT32 x1,
208                                      OPJ_UINT32 y1,
209                                      OPJ_INT32* dest,
210                                      OPJ_UINT32 dest_col_stride,
211                                      OPJ_UINT32 dest_line_stride,
212                                      OPJ_BOOL forgiving)
213 {
214     return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
215             dest,
216             dest_col_stride,
217             dest_line_stride,
218             forgiving,
219             OPJ_TRUE);
220 }
221
222 OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa,
223                                       OPJ_UINT32 x0,
224                                       OPJ_UINT32 y0,
225                                       OPJ_UINT32 x1,
226                                       OPJ_UINT32 y1,
227                                       const OPJ_INT32* src,
228                                       OPJ_UINT32 src_col_stride,
229                                       OPJ_UINT32 src_line_stride,
230                                       OPJ_BOOL forgiving)
231 {
232     return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
233             (OPJ_INT32*)src,
234             src_col_stride,
235             src_line_stride,
236             forgiving,
237             OPJ_FALSE);
238 }