Always pad buffer
[platform/upstream/libaec.git] / src / sz_compat.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "szlib.h"
5
6 #if HAVE_CONFIG_H
7 #  include <config.h>
8 #endif
9
10 #define NOPTS 129
11 #define MIN(a, b) (((a) < (b))? (a): (b))
12
13 static int convert_options(int sz_opts)
14 {
15     int co[NOPTS];
16     int i;
17     int opts = 0;
18
19     memset(co, 0, sizeof(int) * NOPTS);
20     co[SZ_MSB_OPTION_MASK] = AEC_DATA_MSB;
21     co[SZ_NN_OPTION_MASK] = AEC_DATA_PREPROCESS;
22
23     for (i = 1; i < NOPTS; i <<= 1)
24         if (sz_opts & i)
25             opts |= co[i];
26
27     return opts;
28 }
29
30 static int bits_to_bytes(int bit_length)
31 {
32     if (bit_length > 16)
33         return 4;
34     else if (bit_length > 8)
35         return 2;
36     else
37         return 1;
38 }
39
40 static void interleave_buffer(void *dest, const void *src,
41                               size_t n, int wordsize)
42 {
43     size_t i;
44     int j;
45     const unsigned char *src8;
46     unsigned char *dest8;
47
48     src8 = (unsigned char *)src;
49     dest8 = (unsigned char *)dest;
50
51     for (i = 0; i < n / wordsize; i++)
52         for (j = 0; j < wordsize; j++)
53             dest8[j * (n / wordsize) + i] = src8[i * wordsize + j];
54 }
55
56 static void deinterleave_buffer(void *dest, const void *src,
57                                 size_t n, int wordsize)
58 {
59     size_t i;
60     int j;
61     const unsigned char *src8;
62     unsigned char *dest8;
63
64     src8 = (unsigned char *)src;
65     dest8 = (unsigned char *)dest;
66
67     for (i = 0; i < n / wordsize; i++)
68         for (j = 0; j < wordsize; j++)
69             dest8[i * wordsize + j] = src8[j * (n / wordsize) + i];
70 }
71
72 static void add_padding(void *dest, const void *src, size_t src_length,
73                         size_t line_size, size_t padding_size,
74                         int pixel_size, int pp)
75 {
76     size_t i, j, k, ls, ps;
77     const char *pixel;
78     const char zero_pixel[] = {0, 0, 0, 0};
79
80     pixel = zero_pixel;
81     j = 0;
82     i = 0;
83     while (i < src_length) {
84         ls = MIN(src_length - i, line_size);
85         memcpy((char *)dest + j, (char *)src + i, ls);
86         j += ls;
87         i += ls;
88         if (pp)
89             pixel = (char *)src + i - pixel_size;
90         ps = line_size + padding_size - ls;
91         for (k = 0; k < ps; k += pixel_size)
92             memcpy((char *)dest + j + k, pixel, pixel_size);
93         j += ps;
94     }
95 }
96
97 static void remove_padding(void *buf, size_t buf_length,
98                            size_t line_size, size_t padding_size,
99                            int pixel_size)
100 {
101     size_t i, j;
102     size_t padded_line_size = line_size + padding_size;
103
104     i = line_size;
105     for (j = padded_line_size; j < buf_length; j += padded_line_size) {
106         memmove((char *)buf + i, (char *)buf + j, line_size);
107         i += line_size;
108     }
109 }
110
111 int SZ_BufftoBuffCompress(void *dest, size_t *destLen,
112                           const void *source, size_t sourceLen,
113                           SZ_com_t *param)
114 {
115     struct aec_stream strm;
116     int status;
117     int aec_status;
118     void *padbuf;
119     void *buf;
120     size_t padding_size;
121     size_t scanlines;
122     size_t padbuf_size;
123     int pixel_size;
124     int interleave;
125
126     strm.block_size = param->pixels_per_block;
127     strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
128         / param->pixels_per_block;
129     strm.flags = AEC_NOT_ENFORCE | convert_options(param->options_mask);
130     strm.avail_out = *destLen;
131     strm.next_out = dest;
132     buf = 0;
133     padbuf = 0;
134
135     interleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64;
136     if (interleave) {
137         strm.bits_per_sample = 8;
138         buf = malloc(sourceLen);
139         if (buf == NULL) {
140             status = SZ_MEM_ERROR;
141             goto CLEANUP;
142         }
143         interleave_buffer(buf, source, sourceLen, param->bits_per_pixel / 8);
144     } else {
145         strm.bits_per_sample = param->bits_per_pixel;
146         buf = (void *)source;
147     }
148
149     pixel_size = bits_to_bytes(strm.bits_per_sample);
150
151     scanlines = (sourceLen / pixel_size + param->pixels_per_scanline - 1)
152         / param->pixels_per_scanline;
153     padbuf_size = strm.rsi * strm.block_size * pixel_size * scanlines;
154     padbuf = malloc(padbuf_size);
155     if (padbuf == NULL) {
156         status = SZ_MEM_ERROR;
157         goto CLEANUP;
158     }
159
160     padding_size =
161         (strm.rsi * strm.block_size - param->pixels_per_scanline)
162         * pixel_size;
163
164     add_padding(padbuf, buf, sourceLen,
165                 param->pixels_per_scanline * pixel_size,
166                 padding_size, pixel_size,
167                 strm.flags & AEC_DATA_PREPROCESS);
168     strm.next_in = padbuf;
169     strm.avail_in = padbuf_size;
170
171     aec_status = aec_buffer_encode(&strm);
172     if (aec_status == AEC_STREAM_ERROR)
173         status = SZ_OUTBUFF_FULL;
174     else
175         status = aec_status;
176     *destLen = strm.total_out;
177
178 CLEANUP:
179     if (padbuf)
180         free(padbuf);
181     if (interleave && buf)
182         free(buf);
183     return status;
184 }
185
186 int SZ_BufftoBuffDecompress(void *dest, size_t *destLen,
187                             const void *source, size_t sourceLen,
188                             SZ_com_t *param)
189 {
190     struct aec_stream strm;
191     int status;
192     void *buf;
193     size_t padding_size;
194     size_t scanlines;
195     size_t buf_size, total_out;
196     int pixel_size;
197     int pad_scanline;
198     int deinterleave;
199     int extra_buffer;
200
201     strm.block_size = param->pixels_per_block;
202     strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
203         / param->pixels_per_block;
204     strm.flags = convert_options(param->options_mask);
205     strm.avail_in = sourceLen;
206     strm.next_in = source;
207     buf = 0;
208
209     pad_scanline = param->pixels_per_scanline % param->pixels_per_block;
210     deinterleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64;
211     extra_buffer = pad_scanline || deinterleave;
212
213     if (deinterleave)
214         strm.bits_per_sample = 8;
215     else
216         strm.bits_per_sample = param->bits_per_pixel;
217
218     pixel_size = bits_to_bytes(strm.bits_per_sample);
219
220     if (extra_buffer) {
221         if (pad_scanline) {
222             scanlines = (*destLen / pixel_size + param->pixels_per_scanline - 1)
223                 / param->pixels_per_scanline;
224             buf_size = strm.rsi * strm.block_size * pixel_size * scanlines;
225         } else {
226             buf_size = *destLen;
227         }
228         buf = malloc(buf_size);
229         if (buf == NULL) {
230             status = SZ_MEM_ERROR;
231             goto CLEANUP;
232         }
233         strm.next_out = buf;
234         strm.avail_out = buf_size;
235     } else {
236         strm.next_out = dest;
237         strm.avail_out = *destLen;
238     }
239
240     status = aec_buffer_decode(&strm);
241     if (status != AEC_OK)
242         goto CLEANUP;
243
244     if (pad_scanline) {
245         padding_size =
246             (strm.rsi * strm.block_size - param->pixels_per_scanline)
247             * pixel_size;
248         remove_padding(buf, strm.total_out,
249                        param->pixels_per_scanline * pixel_size,
250                        padding_size, pixel_size);
251         total_out = scanlines * param->pixels_per_scanline * pixel_size;
252     } else {
253         total_out = strm.total_out;
254     }
255
256     if (total_out < *destLen)
257         *destLen = total_out;
258
259     if (deinterleave)
260         deinterleave_buffer(dest, buf, *destLen, param->bits_per_pixel / 8);
261     else if (pad_scanline)
262         memcpy(dest, buf, *destLen);
263
264 CLEANUP:
265     if (extra_buffer && buf)
266         free(buf);
267
268     return status;
269 }
270
271 int SZ_encoder_enabled(void)
272 {
273     return 1;
274 }
275
276 /* netcdf searches for SZ_Compress in configure */
277 char SZ_Compress() { return SZ_OK; }