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