sparse_array.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. #include "opj_includes.h"
  32. struct opj_sparse_array_int32 {
  33. OPJ_UINT32 width;
  34. OPJ_UINT32 height;
  35. OPJ_UINT32 block_width;
  36. OPJ_UINT32 block_height;
  37. OPJ_UINT32 block_count_hor;
  38. OPJ_UINT32 block_count_ver;
  39. OPJ_INT32** data_blocks;
  40. };
  41. opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width,
  42. OPJ_UINT32 height,
  43. OPJ_UINT32 block_width,
  44. OPJ_UINT32 block_height)
  45. {
  46. opj_sparse_array_int32_t* sa;
  47. if (width == 0 || height == 0 || block_width == 0 || block_height == 0) {
  48. return NULL;
  49. }
  50. if (block_width > ((OPJ_UINT32)~0U) / block_height / sizeof(OPJ_INT32)) {
  51. return NULL;
  52. }
  53. sa = (opj_sparse_array_int32_t*) opj_calloc(1,
  54. sizeof(opj_sparse_array_int32_t));
  55. sa->width = width;
  56. sa->height = height;
  57. sa->block_width = block_width;
  58. sa->block_height = block_height;
  59. sa->block_count_hor = opj_uint_ceildiv(width, block_width);
  60. sa->block_count_ver = opj_uint_ceildiv(height, block_height);
  61. if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) {
  62. opj_free(sa);
  63. return NULL;
  64. }
  65. sa->data_blocks = (OPJ_INT32**) opj_calloc(sizeof(OPJ_INT32*),
  66. (size_t) sa->block_count_hor * sa->block_count_ver);
  67. if (sa->data_blocks == NULL) {
  68. opj_free(sa);
  69. return NULL;
  70. }
  71. return sa;
  72. }
  73. void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa)
  74. {
  75. if (sa) {
  76. OPJ_UINT32 i;
  77. for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) {
  78. if (sa->data_blocks[i]) {
  79. opj_free(sa->data_blocks[i]);
  80. }
  81. }
  82. opj_free(sa->data_blocks);
  83. opj_free(sa);
  84. }
  85. }
  86. OPJ_BOOL opj_sparse_array_is_region_valid(const opj_sparse_array_int32_t* sa,
  87. OPJ_UINT32 x0,
  88. OPJ_UINT32 y0,
  89. OPJ_UINT32 x1,
  90. OPJ_UINT32 y1)
  91. {
  92. return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width ||
  93. y0 >= sa->height || y1 <= y0 || y1 > sa->height);
  94. }
  95. static OPJ_BOOL opj_sparse_array_int32_read_or_write(
  96. const opj_sparse_array_int32_t* sa,
  97. OPJ_UINT32 x0,
  98. OPJ_UINT32 y0,
  99. OPJ_UINT32 x1,
  100. OPJ_UINT32 y1,
  101. OPJ_INT32* buf,
  102. OPJ_UINT32 buf_col_stride,
  103. OPJ_UINT32 buf_line_stride,
  104. OPJ_BOOL forgiving,
  105. OPJ_BOOL is_read_op)
  106. {
  107. OPJ_UINT32 y, block_y;
  108. OPJ_UINT32 y_incr = 0;
  109. const OPJ_UINT32 block_width = sa->block_width;
  110. if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) {
  111. return forgiving;
  112. }
  113. block_y = y0 / sa->block_height;
  114. for (y = y0; y < y1; block_y ++, y += y_incr) {
  115. OPJ_UINT32 x, block_x;
  116. OPJ_UINT32 x_incr = 0;
  117. OPJ_UINT32 block_y_offset;
  118. y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) :
  119. sa->block_height;
  120. block_y_offset = sa->block_height - y_incr;
  121. y_incr = opj_uint_min(y_incr, y1 - y);
  122. block_x = x0 / block_width;
  123. for (x = x0; x < x1; block_x ++, x += x_incr) {
  124. OPJ_UINT32 j;
  125. OPJ_UINT32 block_x_offset;
  126. OPJ_INT32* src_block;
  127. x_incr = (x == x0) ? block_width - (x0 % block_width) : block_width;
  128. block_x_offset = block_width - x_incr;
  129. x_incr = opj_uint_min(x_incr, x1 - x);
  130. src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x];
  131. if (is_read_op) {
  132. if (src_block == NULL) {
  133. if (buf_col_stride == 1) {
  134. OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride +
  135. (x - x0) * buf_col_stride;
  136. for (j = 0; j < y_incr; j++) {
  137. memset(dest_ptr, 0, sizeof(OPJ_INT32) * x_incr);
  138. dest_ptr += buf_line_stride;
  139. }
  140. } else {
  141. OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride +
  142. (x - x0) * buf_col_stride;
  143. for (j = 0; j < y_incr; j++) {
  144. OPJ_UINT32 k;
  145. for (k = 0; k < x_incr; k++) {
  146. dest_ptr[k * buf_col_stride] = 0;
  147. }
  148. dest_ptr += buf_line_stride;
  149. }
  150. }
  151. } else {
  152. const OPJ_INT32* OPJ_RESTRICT src_ptr = src_block + block_y_offset *
  153. (OPJ_SIZE_T)block_width + block_x_offset;
  154. if (buf_col_stride == 1) {
  155. OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride
  156. +
  157. (x - x0) * buf_col_stride;
  158. if (x_incr == 4) {
  159. /* Same code as general branch, but the compiler */
  160. /* can have an efficient memcpy() */
  161. (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */
  162. for (j = 0; j < y_incr; j++) {
  163. memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
  164. dest_ptr += buf_line_stride;
  165. src_ptr += block_width;
  166. }
  167. } else {
  168. for (j = 0; j < y_incr; j++) {
  169. memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
  170. dest_ptr += buf_line_stride;
  171. src_ptr += block_width;
  172. }
  173. }
  174. } else {
  175. OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride
  176. +
  177. (x - x0) * buf_col_stride;
  178. if (x_incr == 1) {
  179. for (j = 0; j < y_incr; j++) {
  180. *dest_ptr = *src_ptr;
  181. dest_ptr += buf_line_stride;
  182. src_ptr += block_width;
  183. }
  184. } else if (y_incr == 1 && buf_col_stride == 2) {
  185. OPJ_UINT32 k;
  186. for (k = 0; k < (x_incr & ~3U); k += 4) {
  187. dest_ptr[k * buf_col_stride] = src_ptr[k];
  188. dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1];
  189. dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2];
  190. dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3];
  191. }
  192. for (; k < x_incr; k++) {
  193. dest_ptr[k * buf_col_stride] = src_ptr[k];
  194. }
  195. } else if (x_incr >= 8 && buf_col_stride == 8) {
  196. for (j = 0; j < y_incr; j++) {
  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. dest_ptr += buf_line_stride;
  208. src_ptr += block_width;
  209. }
  210. } else {
  211. /* General case */
  212. for (j = 0; j < y_incr; j++) {
  213. OPJ_UINT32 k;
  214. for (k = 0; k < x_incr; k++) {
  215. dest_ptr[k * buf_col_stride] = src_ptr[k];
  216. }
  217. dest_ptr += buf_line_stride;
  218. src_ptr += block_width;
  219. }
  220. }
  221. }
  222. }
  223. } else {
  224. if (src_block == NULL) {
  225. src_block = (OPJ_INT32*) opj_calloc(1,
  226. (size_t) sa->block_width * sa->block_height * sizeof(OPJ_INT32));
  227. if (src_block == NULL) {
  228. return OPJ_FALSE;
  229. }
  230. sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block;
  231. }
  232. if (buf_col_stride == 1) {
  233. OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset *
  234. (OPJ_SIZE_T)block_width + block_x_offset;
  235. const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) *
  236. (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride;
  237. if (x_incr == 4) {
  238. /* Same code as general branch, but the compiler */
  239. /* can have an efficient memcpy() */
  240. (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */
  241. for (j = 0; j < y_incr; j++) {
  242. memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
  243. dest_ptr += block_width;
  244. src_ptr += buf_line_stride;
  245. }
  246. } else {
  247. for (j = 0; j < y_incr; j++) {
  248. memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
  249. dest_ptr += block_width;
  250. src_ptr += buf_line_stride;
  251. }
  252. }
  253. } else {
  254. OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset *
  255. (OPJ_SIZE_T)block_width + block_x_offset;
  256. const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) *
  257. (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride;
  258. if (x_incr == 1) {
  259. for (j = 0; j < y_incr; j++) {
  260. *dest_ptr = *src_ptr;
  261. src_ptr += buf_line_stride;
  262. dest_ptr += block_width;
  263. }
  264. } else if (x_incr >= 8 && buf_col_stride == 8) {
  265. for (j = 0; j < y_incr; j++) {
  266. OPJ_UINT32 k;
  267. for (k = 0; k < (x_incr & ~3U); k += 4) {
  268. dest_ptr[k] = src_ptr[k * buf_col_stride];
  269. dest_ptr[k + 1] = src_ptr[(k + 1) * buf_col_stride];
  270. dest_ptr[k + 2] = src_ptr[(k + 2) * buf_col_stride];
  271. dest_ptr[k + 3] = src_ptr[(k + 3) * buf_col_stride];
  272. }
  273. for (; k < x_incr; k++) {
  274. dest_ptr[k] = src_ptr[k * buf_col_stride];
  275. }
  276. src_ptr += buf_line_stride;
  277. dest_ptr += block_width;
  278. }
  279. } else {
  280. /* General case */
  281. for (j = 0; j < y_incr; j++) {
  282. OPJ_UINT32 k;
  283. for (k = 0; k < x_incr; k++) {
  284. dest_ptr[k] = src_ptr[k * buf_col_stride];
  285. }
  286. src_ptr += buf_line_stride;
  287. dest_ptr += block_width;
  288. }
  289. }
  290. }
  291. }
  292. }
  293. }
  294. return OPJ_TRUE;
  295. }
  296. OPJ_BOOL opj_sparse_array_int32_read(const opj_sparse_array_int32_t* sa,
  297. OPJ_UINT32 x0,
  298. OPJ_UINT32 y0,
  299. OPJ_UINT32 x1,
  300. OPJ_UINT32 y1,
  301. OPJ_INT32* dest,
  302. OPJ_UINT32 dest_col_stride,
  303. OPJ_UINT32 dest_line_stride,
  304. OPJ_BOOL forgiving)
  305. {
  306. return opj_sparse_array_int32_read_or_write(
  307. (opj_sparse_array_int32_t*)sa, x0, y0, x1, y1,
  308. dest,
  309. dest_col_stride,
  310. dest_line_stride,
  311. forgiving,
  312. OPJ_TRUE);
  313. }
  314. OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa,
  315. OPJ_UINT32 x0,
  316. OPJ_UINT32 y0,
  317. OPJ_UINT32 x1,
  318. OPJ_UINT32 y1,
  319. const OPJ_INT32* src,
  320. OPJ_UINT32 src_col_stride,
  321. OPJ_UINT32 src_line_stride,
  322. OPJ_BOOL forgiving)
  323. {
  324. return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
  325. (OPJ_INT32*)src,
  326. src_col_stride,
  327. src_line_stride,
  328. forgiving,
  329. OPJ_FALSE);
  330. }