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