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