option to pad RSI to byte boundary
[platform/upstream/libaec.git] / src / aec.c
1 /**
2  * @file aec.c
3  *
4  * @author Mathis Rosenhauer, Deutsches Klimarechenzentrum
5  * @author Moritz Hanke, Deutsches Klimarechenzentrum
6  * @author Joerg Behrens, Deutsches Klimarechenzentrum
7  * @author Luis Kornblueh, Max-Planck-Institut fuer Meteorologie
8  *
9  * @section LICENSE
10  * Copyright 2012
11  *
12  * Mathis Rosenhauer,                 Luis Kornblueh
13  * Moritz Hanke,
14  * Joerg Behrens
15  *
16  * Deutsches Klimarechenzentrum GmbH  Max-Planck-Institut fuer Meteorologie
17  * Bundesstr. 45a                     Bundesstr. 53
18  * 20146 Hamburg                      20146 Hamburg
19  * Germany                            Germany
20  *
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  *
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice, this list of conditions and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above
30  *    copyright notice, this list of conditions and the following
31  *    disclaimer in the documentation and/or other materials provided
32  *    with the distribution.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
37  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
38  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
39  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
43  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
45  * OF THE POSSIBILITY OF SUCH DAMAGE.
46  *
47  * @section DESCRIPTION
48  *
49  * CLI frontend for Adaptive Entropy Coding library
50  *
51  */
52
53 #include <ctype.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <string.h>
58
59 #ifndef _AIX
60 #include <getopt.h>
61 #endif
62
63 #include <libaec.h>
64
65 #define CHUNK 1024
66
67 int main(int argc, char *argv[])
68 {
69     struct aec_stream strm;
70     unsigned char *in;
71     unsigned char *out;
72     size_t total_out;
73     int chunk, status, c;
74     int input_avail, output_avail;
75     char *outfn, *infn, *ext;
76     FILE *infp, *outfp;
77     int cflag = 0;
78     int dflag = 0;
79
80     chunk = CHUNK;
81     strm.bits_per_sample = 8;
82     strm.block_size = 8;
83     strm.rsi = 2;
84     strm.flags = AEC_DATA_PREPROCESS;
85     opterr = 0;
86
87     while ((c = getopt (argc, argv, "3b:cdj:mn:pr:st")) != -1)
88         switch (c) {
89         case '3':
90             strm.flags |= AEC_DATA_3BYTE;
91             break;
92         case 'b':
93             chunk = atoi(optarg);
94             break;
95         case 'c':
96             cflag = 1;
97             break;
98         case 'd':
99             dflag = 1;
100             break;
101         case 'j':
102             strm.block_size = atoi(optarg);
103             break;
104         case 'm':
105             strm.flags |= AEC_DATA_MSB;
106             break;
107         case 'n':
108             strm.bits_per_sample = atoi(optarg);
109             break;
110         case 'p':
111             strm.flags |= AEC_PAD_RSI;
112             break;
113         case 'r':
114             strm.rsi = atoi(optarg);
115             break;
116         case 's':
117             strm.flags |= AEC_DATA_SIGNED;
118             break;
119         case 't':
120             strm.flags |= AEC_RESTRICTED;
121             break;
122         case '?':
123             if (optopt == 'b')
124                 fprintf (stderr, "Option -%c requires an argument.\n", optopt);
125             else if (isprint (optopt))
126                 fprintf (stderr, "Unknown option `-%c'.\n", optopt);
127             else
128                 fprintf (stderr,
129                          "Unknown option character `\\x%x'.\n",
130                          optopt);
131             return 1;
132         default:
133             abort ();
134         }
135
136     if (optind < argc) {
137         infn = argv[optind];
138     } else {
139         fprintf(stderr, "Usage: %s [OPTION] SOURCE\n", argv[0]);
140         fprintf(stderr, "\nOPTIONS\n");
141         fprintf(stderr, "-3\n   24 bit samples are sored in 3 bytes\n");
142         fprintf(stderr, "-b size\n   internal buffer sizein bytes\n");
143         fprintf(stderr, "-c\n   write output on standard output\n");
144         fprintf(stderr, "-d\n   decode SOURCE. If -d is not used: encode.\n");
145         fprintf(stderr, "-j samples\n   block size in samples\n");
146         fprintf(stderr, "-m\n   samples are MSB first. Default is LSB\n");
147         fprintf(stderr, "-n bits\n   bits per sample\n");
148         fprintf(stderr, "-p\n   pad RSI to byte boundary\n");
149         fprintf(stderr, "-r blocks\n   reference sample interval in blocks\n");
150         fprintf(stderr, "-s\n   samples are signed. Default is unsigned\n");
151         fprintf(stderr, "-t\n   use restricted set of code options\n\n");
152         exit(-1);
153     }
154
155     if (strm.bits_per_sample > 16) {
156         if (strm.bits_per_sample <= 24 && strm.flags & AEC_DATA_3BYTE)
157             chunk *= 3;
158         else
159             chunk *= 4;
160     } else if (strm.bits_per_sample > 8) {
161         chunk *= 2;
162     }
163
164     out = (unsigned char *)malloc(chunk);
165     in = (unsigned char *)malloc(chunk);
166
167
168     if (in == NULL || out == NULL)
169         exit(-1);
170
171     total_out = 0;
172     strm.avail_in = 0;
173     strm.avail_out = chunk;
174     strm.next_out = out;
175
176     input_avail = 1;
177     output_avail = 1;
178
179     if ((infp = fopen(infn, "r")) == NULL)
180         exit(-1);
181
182     if (cflag) {
183         outfp = stdout;
184     } else {
185         outfn = malloc(strlen(infn) + 4);
186         if (outfn == NULL)
187             exit(-1);
188
189         if (dflag) {
190             if ((ext = strstr(infn, ".rz")) == NULL) {
191                 fprintf(stderr, "ERROR: input file needs to end with .rz\n");
192                 exit(-1);
193             }
194             strncpy(outfn, infn, ext - infn);
195         } else {
196             sprintf(outfn, "%s.rz", infn);
197         }
198
199         if ((outfp = fopen(outfn, "w")) == NULL)
200             exit(-1);
201     }
202
203     if (dflag) {
204         if (aec_decode_init(&strm) != AEC_OK) {
205             fprintf(stderr, "ERROR: Initialization failed\n");
206             return 1;
207         }
208     } else {
209         if (aec_encode_init(&strm) != AEC_OK) {
210             fprintf(stderr, "ERROR: Initialization failed\n");
211             return 1;
212         }
213     }
214
215     while(input_avail || output_avail) {
216         if (strm.avail_in == 0 && input_avail) {
217             strm.avail_in = fread(in, 1, chunk, infp);
218             if (strm.avail_in != chunk)
219                 input_avail = 0;
220             strm.next_in = in;
221         }
222
223         if (dflag)
224             status = aec_decode(&strm, AEC_NO_FLUSH);
225         else
226             status = aec_encode(&strm, AEC_NO_FLUSH);
227
228         if (status != AEC_OK) {
229             fprintf(stderr, "ERROR: %i\n", status);
230             return 1;
231         }
232
233         if (strm.total_out - total_out > 0) {
234             fwrite(out, strm.total_out - total_out, 1, outfp);
235             total_out = strm.total_out;
236             output_avail = 1;
237             strm.next_out = out;
238             strm.avail_out = chunk;
239         } else {
240             output_avail = 0;
241         }
242
243     }
244
245     if (dflag) {
246         aec_decode_end(&strm);
247     } else {
248         if ((status = aec_encode(&strm, AEC_FLUSH)) != AEC_OK) {
249             fprintf(stderr, "ERROR: %i\n", status);
250             return 1;
251         }
252
253         if (strm.total_out - total_out > 0)
254             fwrite(out, strm.total_out - total_out, 1, outfp);
255
256         aec_encode_end(&strm);
257     }
258
259     fclose(infp);
260     fclose(outfp);
261     free(in);
262     free(out);
263     if (!cflag) {
264         unlink(infn);
265         free(outfn);
266     }
267     return 0;
268 }