1 /**
2 * @file sz_compat.c
3 *
4 * @section LICENSE
5 * Copyright 2021 Mathis Rosenhauer, Moritz Hanke, Joerg Behrens, Luis Kornblueh
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * @section DESCRIPTION
33 *
34 * Adaptive Entropy Coding library
35 *
36 */
37
38 #include "config.h"
39 #include "szlib.h"
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #define NOPTS 129
45 #define MIN(a, b) (((a) < (b))? (a): (b))
46
convert_options(int sz_opts)47 static int convert_options(int sz_opts)
48 {
49 int co[NOPTS];
50 int opts = 0;
51
52 memset(co, 0, sizeof(int) * NOPTS);
53 co[SZ_MSB_OPTION_MASK] = AEC_DATA_MSB;
54 co[SZ_NN_OPTION_MASK] = AEC_DATA_PREPROCESS;
55
56 for (int i = 1; i < NOPTS; i <<= 1)
57 if (sz_opts & i)
58 opts |= co[i];
59
60 return opts;
61 }
62
bits_to_bytes(int bit_length)63 static int bits_to_bytes(int bit_length)
64 {
65 if (bit_length > 16)
66 return 4;
67 else if (bit_length > 8)
68 return 2;
69 else
70 return 1;
71 }
72
interleave_buffer(void * dest,const void * src,size_t n,int wordsize)73 static void interleave_buffer(void *dest, const void *src,
74 size_t n, int wordsize)
75 {
76 const unsigned char *src8 = (unsigned char *)src;
77 unsigned char *dest8 = (unsigned char *)dest;
78
79 for (size_t i = 0; i < n / wordsize; i++)
80 for (size_t j = 0; j < wordsize; j++)
81 dest8[j * (n / wordsize) + i] = src8[i * wordsize + j];
82 }
83
deinterleave_buffer(void * dest,const void * src,size_t n,int wordsize)84 static void deinterleave_buffer(void *dest, const void *src,
85 size_t n, int wordsize)
86 {
87 const unsigned char *src8 = (unsigned char *)src;
88 unsigned char *dest8 = (unsigned char *)dest;
89
90 for (size_t i = 0; i < n / wordsize; i++)
91 for (size_t j = 0; j < wordsize; j++)
92 dest8[i * wordsize + j] = src8[j * (n / wordsize) + i];
93 }
94
add_padding(void * dest,const void * src,size_t src_length,size_t line_size,size_t padding_size,int pixel_size,int pp)95 static void add_padding(void *dest, const void *src, size_t src_length,
96 size_t line_size, size_t padding_size,
97 int pixel_size, int pp)
98 {
99 const char zero_pixel[] = {0, 0, 0, 0};
100
101 const char *pixel = zero_pixel;
102 size_t j = 0;
103 size_t i = 0;
104 while (i < src_length) {
105 size_t ps;
106 size_t ls = MIN(src_length - i, line_size);
107 memcpy((char *)dest + j, (char *)src + i, ls);
108 j += ls;
109 i += ls;
110 if (pp)
111 pixel = (char *)src + i - pixel_size;
112 ps = line_size + padding_size - ls;
113 for (size_t k = 0; k < ps; k += pixel_size)
114 memcpy((char *)dest + j + k, pixel, pixel_size);
115 j += ps;
116 }
117 }
118
remove_padding(void * buf,size_t buf_length,size_t line_size,size_t padding_size,int pixel_size)119 static void remove_padding(void *buf, size_t buf_length,
120 size_t line_size, size_t padding_size,
121 int pixel_size)
122 {
123 size_t padded_line_size = line_size + padding_size;
124
125 size_t i = line_size;
126 for (size_t j = padded_line_size; j < buf_length; j += padded_line_size) {
127 memmove((char *)buf + i, (char *)buf + j, line_size);
128 i += line_size;
129 }
130 }
131
SZ_BufftoBuffCompress(void * dest,size_t * destLen,const void * source,size_t sourceLen,SZ_com_t * param)132 int SZ_BufftoBuffCompress(void *dest, size_t *destLen,
133 const void *source, size_t sourceLen,
134 SZ_com_t *param)
135 {
136 struct aec_stream strm;
137 void *buf = 0;
138 void *padbuf = 0;
139 int status;
140 int interleave;
141 int pixel_size;
142 int aec_status;
143 size_t scanlines;
144 size_t padbuf_size;
145 size_t padding_size;
146
147 strm.block_size = param->pixels_per_block;
148 strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
149 / param->pixels_per_block;
150 strm.flags = AEC_NOT_ENFORCE | convert_options(param->options_mask);
151 strm.avail_out = *destLen;
152 strm.next_out = dest;
153
154 interleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64;
155 if (interleave) {
156 strm.bits_per_sample = 8;
157 buf = malloc(sourceLen);
158 if (buf == NULL) {
159 status = SZ_MEM_ERROR;
160 goto CLEANUP;
161 }
162 interleave_buffer(buf, source, sourceLen, param->bits_per_pixel / 8);
163 } else {
164 strm.bits_per_sample = param->bits_per_pixel;
165 buf = (void *)source;
166 }
167
168 pixel_size = bits_to_bytes(strm.bits_per_sample);
169
170 scanlines = (sourceLen / pixel_size + param->pixels_per_scanline - 1)
171 / param->pixels_per_scanline;
172 padbuf_size = strm.rsi * strm.block_size * pixel_size * scanlines;
173 padbuf = malloc(padbuf_size);
174 if (padbuf == NULL) {
175 status = SZ_MEM_ERROR;
176 goto CLEANUP;
177 }
178
179 padding_size =
180 (strm.rsi * strm.block_size - param->pixels_per_scanline)
181 * pixel_size;
182
183 add_padding(padbuf, buf, sourceLen,
184 param->pixels_per_scanline * pixel_size,
185 padding_size, pixel_size,
186 strm.flags & AEC_DATA_PREPROCESS);
187 strm.next_in = padbuf;
188 strm.avail_in = padbuf_size;
189
190 aec_status = aec_buffer_encode(&strm);
191 if (aec_status == AEC_STREAM_ERROR)
192 status = SZ_OUTBUFF_FULL;
193 else
194 status = aec_status;
195 *destLen = strm.total_out;
196
197 CLEANUP:
198 if (padbuf)
199 free(padbuf);
200 if (interleave && buf)
201 free(buf);
202 return status;
203 }
204
SZ_BufftoBuffDecompress(void * dest,size_t * destLen,const void * source,size_t sourceLen,SZ_com_t * param)205 int SZ_BufftoBuffDecompress(void *dest, size_t *destLen,
206 const void *source, size_t sourceLen,
207 SZ_com_t *param)
208 {
209 struct aec_stream strm;
210 void *buf = 0;
211 int status;
212 int pad_scanline;
213 int deinterleave;
214 int extra_buffer;
215 int pixel_size;
216 size_t total_out;
217 size_t scanlines;
218
219 strm.block_size = param->pixels_per_block;
220 strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
221 / param->pixels_per_block;
222 strm.flags = convert_options(param->options_mask);
223 strm.avail_in = sourceLen;
224 strm.next_in = source;
225
226 pad_scanline = param->pixels_per_scanline % param->pixels_per_block;
227 deinterleave = (param->bits_per_pixel == 32
228 || param->bits_per_pixel == 64);
229 extra_buffer = pad_scanline || deinterleave;
230
231 if (deinterleave)
232 strm.bits_per_sample = 8;
233 else
234 strm.bits_per_sample = param->bits_per_pixel;
235 pixel_size = bits_to_bytes(strm.bits_per_sample);
236
237
238 if (extra_buffer) {
239 size_t buf_size;
240 if (pad_scanline) {
241 scanlines = (*destLen / pixel_size + param->pixels_per_scanline - 1)
242 / param->pixels_per_scanline;
243 buf_size = strm.rsi * strm.block_size * pixel_size * scanlines;
244 } else {
245 buf_size = *destLen;
246 }
247 buf = malloc(buf_size);
248 if (buf == NULL) {
249 status = SZ_MEM_ERROR;
250 goto CLEANUP;
251 }
252 strm.next_out = buf;
253 strm.avail_out = buf_size;
254 } else {
255 strm.next_out = dest;
256 strm.avail_out = *destLen;
257 }
258
259 status = aec_buffer_decode(&strm);
260 if (status != AEC_OK)
261 goto CLEANUP;
262
263 if (pad_scanline) {
264 size_t padding_size =
265 (strm.rsi * strm.block_size - param->pixels_per_scanline)
266 * pixel_size;
267 remove_padding(buf, strm.total_out,
268 param->pixels_per_scanline * pixel_size,
269 padding_size, pixel_size);
270 total_out = scanlines * param->pixels_per_scanline * pixel_size;
271 } else {
272 total_out = strm.total_out;
273 }
274
275 if (total_out < *destLen)
276 *destLen = total_out;
277
278 if (deinterleave)
279 deinterleave_buffer(dest, buf, *destLen, param->bits_per_pixel / 8);
280 else if (pad_scanline)
281 memcpy(dest, buf, *destLen);
282
283 CLEANUP:
284 if (extra_buffer && buf)
285 free(buf);
286
287 return status;
288 }
289
SZ_encoder_enabled(void)290 int SZ_encoder_enabled(void)
291 {
292 return 1;
293 }
294
295 /* netcdf searches for SZ_Compress in configure */
SZ_Compress()296 char SZ_Compress() { return SZ_OK; }
297