add support for MD5 checking and a test mode
[platform/upstream/flac.git] / src / flac / decode.c
1 /* flac - Command-line FLAC encoder/decoder
2  * Copyright (C) 2000  Josh Coalson
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19 #if defined _WIN32 && !defined __CYGWIN__
20 /* where MSVC puts unlink() */
21 # include <io.h>
22 #else
23 # include <unistd.h>
24 #endif
25 #include <stdio.h> /* for FILE */
26 #include <string.h> /* for strcmp() */
27 #include "FLAC/all.h"
28 #include "decode.h"
29
30 typedef struct {
31         FILE *fout;
32         bool abort_flag;
33         bool test_only;
34         bool is_wave_out;
35         bool is_big_endian;
36         bool is_unsigned_samples;
37         uint64 total_samples;
38         unsigned bps;
39         unsigned channels;
40         unsigned sample_rate;
41         bool verbose;
42         uint64 skip;
43         uint64 samples_processed;
44         unsigned frame_counter;
45 } stream_info_struct;
46
47 static FLAC__FileDecoder *decoder;
48 static bool is_big_endian_host;
49
50 /* local routines */
51 static bool init(const char *infile, stream_info_struct *stream_info);
52 static bool write_little_endian_uint16(FILE *f, uint16 val);
53 static bool write_little_endian_uint32(FILE *f, uint32 val);
54 static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
55 static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
56 static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
57 static void print_stats(const stream_info_struct *stream_info);
58
59 int decode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip)
60 {
61         bool md5_failure = false;
62         stream_info_struct stream_info;
63
64         decoder = 0;
65         stream_info.abort_flag = false;
66         stream_info.test_only = (outfile == 0);
67         stream_info.is_wave_out = true;
68         stream_info.verbose = verbose;
69         stream_info.skip = skip;
70         stream_info.samples_processed = 0;
71         stream_info.frame_counter = 0;
72
73         if(!stream_info.test_only) {
74                 if(0 == strcmp(outfile, "-")) {
75                         stream_info.fout = stdout;
76                 }
77                 else {
78                         if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
79                                 fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
80                                 return false;
81                         }
82                 }
83         }
84
85         if(!init(infile, &stream_info))
86                 goto wav_abort_;
87
88         if(skip > 0) {
89                 if(!FLAC__file_decoder_process_metadata(decoder)) {
90                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
91                         goto wav_abort_;
92                 }
93                 if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
94                         fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
95                         goto wav_abort_;
96                 }
97                 if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
98                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
99                         goto wav_abort_;
100                 }
101                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
102                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
103                         goto wav_abort_;
104                 }
105         }
106         else {
107                 if(!FLAC__file_decoder_process_whole_file(decoder)) {
108                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
109                         goto wav_abort_;
110                 }
111                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
112                         fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
113                         goto wav_abort_;
114                 }
115         }
116
117         if(decoder) {
118                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
119                         md5_failure = !FLAC__file_decoder_finish(decoder);
120                 print_stats(&stream_info);
121                 FLAC__file_decoder_free_instance(decoder);
122         }
123         if(!stream_info.test_only)
124                 fclose(stream_info.fout);
125         if(verbose)
126                 printf("\n");
127         fflush(stdout);
128         if(md5_failure) {
129                 fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
130                 return 1;
131         }
132         else {
133                 if(stream_info.test_only)
134                         printf("%s: ok\n", infile);
135         }
136         return 0;
137 wav_abort_:
138         if(decoder) {
139                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
140                         FLAC__file_decoder_finish(decoder);
141                 FLAC__file_decoder_free_instance(decoder);
142         }
143         if(!stream_info.test_only) {
144                 fclose(stream_info.fout);
145                 unlink(outfile);
146         }
147         return 1;
148 }
149
150 int decode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples)
151 {
152         bool md5_failure = false;
153         stream_info_struct stream_info;
154
155         decoder = 0;
156         stream_info.abort_flag = false;
157         stream_info.test_only = (outfile == 0);
158         stream_info.is_wave_out = false;
159         stream_info.is_big_endian = is_big_endian;
160         stream_info.is_unsigned_samples = is_unsigned_samples;
161         stream_info.verbose = verbose;
162         stream_info.skip = skip;
163         stream_info.samples_processed = 0;
164         stream_info.frame_counter = 0;
165
166         if(!stream_info.test_only) {
167                 if(0 == strcmp(outfile, "-")) {
168                         stream_info.fout = stdout;
169                 }
170                 else {
171                         if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
172                                 fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
173                                 return false;
174                         }
175                 }
176         }
177
178         if(!init(infile, &stream_info))
179                 goto raw_abort_;
180
181         if(skip > 0) {
182                 if(!FLAC__file_decoder_process_metadata(decoder)) {
183                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
184                         goto raw_abort_;
185                 }
186                 if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
187                         fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
188                         goto raw_abort_;
189                 }
190                 if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
191                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
192                         goto raw_abort_;
193                 }
194                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
195                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
196                         goto raw_abort_;
197                 }
198         }
199         else {
200                 if(!FLAC__file_decoder_process_whole_file(decoder)) {
201                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
202                         goto raw_abort_;
203                 }
204                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
205                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
206                         goto raw_abort_;
207                 }
208         }
209
210         if(decoder) {
211                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
212                         md5_failure = !FLAC__file_decoder_finish(decoder);
213                 print_stats(&stream_info);
214                 FLAC__file_decoder_free_instance(decoder);
215         }
216         if(!stream_info.test_only)
217                 fclose(stream_info.fout);
218         if(verbose)
219                 printf("\n");
220         fflush(stdout);
221         if(md5_failure) {
222                 fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
223                 return 1;
224         }
225         else {
226                 if(stream_info.test_only)
227                         printf("%s: ok\n", infile);
228         }
229         return 0;
230 raw_abort_:
231         if(decoder) {
232                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
233                         FLAC__file_decoder_finish(decoder);
234                 FLAC__file_decoder_free_instance(decoder);
235         }
236         if(!stream_info.test_only) {
237                 fclose(stream_info.fout);
238                 unlink(outfile);
239         }
240         return 1;
241 }
242
243 bool init(const char *infile, stream_info_struct *stream_info)
244 {
245         uint32 test = 1;
246
247         is_big_endian_host = (*((byte*)(&test)))? false : true;
248
249         decoder = FLAC__file_decoder_get_new_instance();
250         if(0 == decoder) {
251                 fprintf(stderr, "ERROR creating the decoder instance\n");
252                 return false;
253         }
254         decoder->check_md5 = true;
255
256         if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, stream_info) != FLAC__FILE_DECODER_OK) {
257                 fprintf(stderr, "ERROR initializing decoder, state = %d\n", decoder->state);
258                 return false;
259         }
260
261         return true;
262 }
263
264 bool write_little_endian_uint16(FILE *f, uint16 val)
265 {
266         byte *b = (byte*)(&val);
267         if(is_big_endian_host) {
268                 byte tmp;
269                 tmp = b[1]; b[1] = b[0]; b[0] = tmp;
270         }
271         return fwrite(b, 1, 2, f) == 2;
272 }
273
274 bool write_little_endian_uint32(FILE *f, uint32 val)
275 {
276         byte *b = (byte*)(&val);
277         if(is_big_endian_host) {
278                 byte tmp;
279                 tmp = b[3]; b[3] = b[0]; b[0] = tmp;
280                 tmp = b[2]; b[2] = b[1]; b[1] = tmp;
281         }
282         return fwrite(b, 1, 4, f) == 4;
283 }
284
285 FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
286 {
287         stream_info_struct *stream_info = (stream_info_struct *)client_data;
288         FILE *fout = stream_info->fout;
289         unsigned bps = stream_info->bps, channels = stream_info->channels;
290         bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian);
291         bool is_unsigned_samples = (stream_info->is_wave_out? bps==8 : stream_info->is_unsigned_samples);
292         unsigned wide_samples = header->blocksize, wide_sample, sample, channel, byte;
293         static signed char scbuffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * ((FLAC__MAX_BITS_PER_SAMPLE+7)>>3)]; /* WATCHOUT: can be up to 2 megs */
294         unsigned char *ucbuffer = (unsigned char *)scbuffer;
295         signed short *ssbuffer = (signed short *)scbuffer;
296         unsigned short *usbuffer = (unsigned short *)scbuffer;
297
298         (void)decoder;
299
300         if(stream_info->abort_flag)
301                 return FLAC__STREAM_DECODER_WRITE_ABORT;
302
303         stream_info->samples_processed += wide_samples;
304         stream_info->frame_counter++;
305
306         if(stream_info->verbose && !(stream_info->frame_counter & 0x1f))
307                 print_stats(stream_info);
308
309         if(!stream_info->test_only) {
310                 if(bps == 8) {
311                         if(is_unsigned_samples) {
312                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
313                                         for(channel = 0; channel < channels; channel++, sample++)
314                                                 ucbuffer[sample] = buffer[channel][wide_sample] + 128;
315                         }
316                         else {
317                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
318                                         for(channel = 0; channel < channels; channel++, sample++)
319                                                 scbuffer[sample] = buffer[channel][wide_sample];
320                         }
321                         if(fwrite(ucbuffer, 1, sample, fout) != sample)
322                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
323                 }
324                 else { /* bps == 16 */
325                         if(is_unsigned_samples) {
326                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
327                                         for(channel = 0; channel < channels; channel++, sample++)
328                                                 usbuffer[sample] = buffer[channel][wide_sample] + 32768;
329                         }
330                         else {
331                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
332                                         for(channel = 0; channel < channels; channel++, sample++)
333                                                 ssbuffer[sample] = buffer[channel][wide_sample];
334                         }
335                         if(is_big_endian != is_big_endian_host) {
336                                 unsigned char tmp;
337                                 for(byte = 0; byte < sample<<1; byte += 2) {
338                                         tmp = ucbuffer[byte];
339                                         ucbuffer[byte] = ucbuffer[byte+1];
340                                         ucbuffer[byte+1] = tmp;
341                                 }
342                         }
343                         if(fwrite(usbuffer, 2, sample, fout) != sample)
344                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
345                 }
346         }
347         return FLAC__STREAM_DECODER_WRITE_CONTINUE;
348 }
349
350 void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
351 {
352         stream_info_struct *stream_info = (stream_info_struct *)client_data;
353         (void)decoder;
354         if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
355                 stream_info->total_samples = metadata->data.encoding.total_samples - stream_info->skip;
356                 stream_info->bps = metadata->data.encoding.bits_per_sample;
357                 stream_info->channels = metadata->data.encoding.channels;
358                 stream_info->sample_rate = metadata->data.encoding.sample_rate;
359
360                 if(stream_info->bps != 8 && stream_info->bps != 16) {
361                         fprintf(stderr, "ERROR: bits per sample is not 8 or 16\n");
362                         stream_info->abort_flag = true;
363                         return;
364                 }
365
366                 /* write the WAVE headers if necessary */
367                 if(!stream_info->test_only && stream_info->is_wave_out) {
368                         uint64 data_size = stream_info->total_samples * stream_info->channels * ((stream_info->bps+7)/8);
369                         if(data_size >= 0xFFFFFFDC) {
370                                 fprintf(stderr, "ERROR: stream is too big for a wave file\n");
371                                 stream_info->abort_flag = true;
372                                 return;
373                         }
374                         if(fwrite("RIFF", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
375                         if(!write_little_endian_uint32(stream_info->fout, (uint32)(data_size+36))) stream_info->abort_flag = true; /* filesize-8 */
376                         if(fwrite("WAVEfmt ", 1, 8, stream_info->fout) != 8) stream_info->abort_flag = true;
377                         if(fwrite("\020\000\000\000", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; /* chunk size = 16 */
378                         if(fwrite("\001\000", 1, 2, stream_info->fout) != 2) stream_info->abort_flag = true; /* compression code == 1 */
379                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels))) stream_info->abort_flag = true;
380                         if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate)) stream_info->abort_flag = true;
381                         if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate * stream_info->channels * ((stream_info->bps+7) / 8))) stream_info->abort_flag = true; /* @@@ or is it (sample_rate*channels*bps) / 8 ??? */
382                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels * ((stream_info->bps+7) / 8)))) stream_info->abort_flag = true; /* block align */
383                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->bps))) stream_info->abort_flag = true; /* bits per sample */
384                         if(fwrite("data", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
385                         if(!write_little_endian_uint32(stream_info->fout, (uint32)data_size)) stream_info->abort_flag = true; /* data size */
386                 }
387         }
388 }
389
390 void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
391 {
392         stream_info_struct *stream_info = (stream_info_struct *)client_data;
393         (void)decoder;
394         fprintf(stderr, "*** Got error code %d\n", status);
395         stream_info->abort_flag = true;
396 }
397
398 void print_stats(const stream_info_struct *stream_info)
399 {
400         if(stream_info->verbose) {
401                 printf("\r%s %u of %u samples, %6.2f%% complete",
402                         stream_info->test_only? "tested" : "wrote",
403                         (unsigned)stream_info->samples_processed,
404                         (unsigned)stream_info->total_samples,
405 #ifdef _MSC_VER
406                         /* with VC++ you have to spoon feed it the casting */
407                         (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0
408 #else
409                         (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0
410 #endif
411                 );
412                 fflush(stdout);
413         }
414 }