fix bug in stats reporting
[flac.git] / src / flac / decode.c
1 /* flac - Command-line FLAC encoder/decoder
2  * Copyright (C) 2000,2001,2002  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 <math.h> /* for floor() */
26 #include <stdio.h> /* for FILE et al. */
27 #include <string.h> /* for strcmp() */
28 #include "FLAC/all.h"
29 #include "decode.h"
30 #include "file.h"
31 #ifdef FLAC__HAS_OGG
32 #include "OggFLAC/stream_decoder.h"
33 #endif
34
35 typedef struct {
36 #ifdef FLAC__HAS_OGG
37         FLAC__bool is_ogg;
38 #endif
39
40         FLAC__bool verbose;
41         FLAC__bool is_wave_out;
42         FLAC__bool continue_through_decode_errors;
43         FLAC__bool test_only;
44         FLAC__bool analysis_mode;
45         analysis_options aopts;
46         FLAC__uint64 skip;
47
48         const char *inbasefilename;
49
50         FLAC__uint64 samples_processed;
51         unsigned frame_counter;
52         FLAC__bool abort_flag;
53
54         struct {
55                 FLAC__bool needs_fixup;
56                 unsigned riff_offset;
57                 unsigned data_offset;
58         } wave_chunk_size_fixup;
59
60         FLAC__bool is_big_endian;
61         FLAC__bool is_unsigned_samples;
62         FLAC__uint64 total_samples;
63         unsigned bps;
64         unsigned channels;
65         unsigned sample_rate;
66
67         union {
68                 union {
69                         FLAC__FileDecoder *file;
70                 } flac;
71 #ifdef FLAC__HAS_OGG
72                 union {
73                         OggFLAC__StreamDecoder *stream;
74                 } ogg;
75 #endif
76         } decoder;
77
78 #ifdef FLAC__HAS_OGG
79         FILE *fin;
80 #endif
81         FILE *fout;
82 } DecoderSession;
83
84
85 static FLAC__bool is_big_endian_host_;
86
87
88 /*
89  * local routines
90  */
91 static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool verbose, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, FLAC__bool analysis_mode, analysis_options aopts, FLAC_uint64 skip, const char *infilename, const char *outfilename);
92 static void DecoderSession_destroy(DecoderSession *d);
93 static FLAC__bool DecoderSession_init_decoder(const char *infilename, DecoderSession *decoder_session);
94 static int DecoderSession_finish_ok(DecoderSession *d, int info_align_carry, int info_align_zero);
95 static int DecoderSession_finish_error(DecoderSession *d);
96 static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
97 static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
98 static FLAC__bool fixup_wave_chunk_size(const char *outfilename, unsigned riff_offset, unsigned data_offset, FLAC__uint32 data_size);
99 #ifdef FLAC__HAS_OGG
100 static FLAC__StreamDecoderReadStatus read_callback(const OggFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
101 #endif
102 /*
103  * We use 'void *' so that we can use the same callbacks for the
104  * FLAC__StreamDecoder and FLAC__FileDecoder.  The 'decoder' argument is
105  * actually never used in the callbacks.
106  */
107 static FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
108 static void metadata_callback(const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
109 static void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
110 static void print_stats(const DecoderSession *decoder_session);
111
112
113 /*
114  * public routines
115  */
116 int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
117 {
118         FLAC__bool md5_failure = false;
119         DecoderSession decoder_session;
120
121         if(!DecoderSession_construct(options.common.verbose, /*is_wave_out=*/true, options.common.continue_through_decode_errors, analysis_mode, aopts, options.common.skip, infilename, outfilename))
122                 return 1;
123
124         if(!DecoderSession_init_decoder(&decoder_session, infilename))
125                 return DecoderSession_finish_error(&decoder_session);
126
127         if(decoder_session.skip > 0) {
128 #ifdef FLAC__HAS_OGG
129                 if(decoder_session.is_ogg) { /*@@@ (move this check into main.c) */
130                         fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", decoder_session.inbasefilename);
131                         goto wav_abort_;
132                 }
133 #endif
134                 if(!FLAC__file_decoder_process_until_end_of_metadata(decoder_session.decoder.file)) {
135                         fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
136                         goto wav_abort_;
137                 }
138                 if(decoder_session.abort_flag)
139                         goto wav_abort_;
140                 if(!FLAC__file_decoder_seek_absolute(decoder_session.decoder.file, decoder_session.skip)) {
141                         fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
142                         goto wav_abort_;
143                 }
144                 if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
145                         if(decoder_session.verbose) fprintf(stderr, "\n");
146                         fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
147                         goto wav_abort_;
148                 }
149                 if(FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
150                         if(decoder_session.verbose) fprintf(stderr, "\n");
151                         fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
152                         goto wav_abort_;
153                 }
154         }
155         else {
156 #ifdef FLAC__HAS_OGG
157                 if(decoder_session.is_ogg) {
158                         if(!OggFLAC__stream_decoder_process_until_end_of_stream(decoder_session.decoder.stream)) {
159                                 if(decoder_session.verbose) fprintf(stderr, "\n");
160                                 fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", decoder_session.inbasefilename, OggFLAC__stream_decoder_get_state(decoder_session.decoder.stream), FLAC__StreamDecoderStateString[OggFLAC__stream_decoder_get_state(decoder_session.decoder.stream)]);
161                                 goto wav_abort_;
162                         }
163                         if(OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream) != FLAC__STREAM_DECODER_END_OF_STREAM) {
164                                 if(decoder_session.verbose) fprintf(stderr, "\n");
165                                 fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", decoder_session.inbasefilename, OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream), FLAC__StreamDecoderStateString[OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream)]);
166                                 goto wav_abort_;
167                         }
168                 }
169                 else
170 #endif
171                 {
172                         if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
173                                 if(decoder_session.verbose) fprintf(stderr, "\n");
174                                 fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
175                                 goto wav_abort_;
176                         }
177                         if(FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
178                                 if(decoder_session.verbose) fprintf(stderr, "\n");
179                                 fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
180                                 goto wav_abort_;
181                         }
182                 }
183         }
184
185 #ifdef FLAC__HAS_OGG
186         if(decoder_session.is_ogg) {
187                 if(decoder_session.decoder.stream) {
188                         OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
189                         md5_failure = false;
190                         print_stats(&decoder_session);
191                         OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
192                 }
193         }
194         else
195 #endif
196         {
197                 if(decoder_session.decoder.file) {
198                         md5_failure = !FLAC__file_decoder_finish(decoder_session.decoder.file);
199                         print_stats(&decoder_session);
200                         FLAC__file_decoder_delete(decoder_session.decoder.file);
201                 }
202         }
203         if(0 != decoder_session.fout && decoder_session.fout != stdout)
204                 fclose(decoder_session.fout);
205 #ifdef FLAC__HAS_OGG
206         if(decoder_session.is_ogg) {
207                 if(0 != decoder_session.fin && decoder_session.fin != stdin)
208                         fclose(decoder_session.fin);
209         }
210 #endif
211         if(analysis_mode)
212                 flac__analyze_finish(aopts);
213         if(decoder_session.wave_chunk_size_fixup.needs_fixup)
214                 if(!fixup_wave_chunk_size(outfilename, decoder_session.wave_chunk_size_fixup.riff_offset, decoder_session.wave_chunk_size_fixup.data_offset, (FLAC__uint32)decoder_session.samples_processed))
215                         return 1;
216         if(md5_failure) {
217                 fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", decoder_session.inbasefilename);
218         }
219         else {
220                 if(decoder_session.verbose)
221                         fprintf(stderr, "\r%s: %s         \n", decoder_session.inbasefilename, decoder_session.test_only? "ok           ":analysis_mode?"done           ":"done");
222         }
223         return 0;
224 wav_abort_:
225 #ifdef FLAC__HAS_OGG
226         if(decoder_session.is_ogg) {
227                 if(decoder_session.decoder.stream) {
228                         OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
229                         OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
230                 }
231         }
232         else
233 #endif
234         {
235                 if(decoder_session.decoder.file) {
236                         FLAC__file_decoder_finish(decoder_session.decoder.file);
237                         FLAC__file_decoder_delete(decoder_session.decoder.file);
238                 }
239         }
240         if(0 != decoder_session.fout && decoder_session.fout != stdout) {
241                 fclose(decoder_session.fout);
242                 unlink(outfilename);
243         }
244 #ifdef FLAC__HAS_OGG
245         if(decoder_session.is_ogg) {
246                 if(0 != decoder_session.fin && decoder_session.fin != stdin)
247                         fclose(decoder_session.fin);
248         }
249 #endif
250         if(analysis_mode)
251                 flac__analyze_finish(aopts);
252         return 1;
253 }
254
255 int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options)
256 {
257         FLAC__bool md5_failure = false;
258         DecoderSession decoder_session;
259
260         decoder_session.is_big_endian = options.is_big_endian;
261         decoder_session.is_unsigned_samples = options.is_unsigned_samples;
262
263         if(!DecoderSession_construct(options.common.verbose, /*is_wave_out=*/false, options.common.continue_through_decode_errors, analysis_mode, aopts, options.common.skip, infilename, outfilename))
264                 return 1;
265
266         if(!DecoderSession_init_decoder(&decoder_session, infilename))
267                 return DecoderSession_finish_error(&decoder_session);
268
269         if(decoder_session.skip > 0) {
270 #ifdef FLAC__HAS_OGG
271                 if(decoder_session.is_ogg) { /*@@@ (move this check into main.c) */
272                         fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", decoder_session.inbasefilename);
273                         goto raw_abort_;
274                 }
275 #endif
276                 if(!FLAC__file_decoder_process_until_end_of_metadata(decoder_session.decoder.file)) {
277                         fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
278                         goto raw_abort_;
279                 }
280                 if(decoder_session.abort_flag)
281                         goto raw_abort_;
282                 if(!FLAC__file_decoder_seek_absolute(decoder_session.decoder.file, decoder_session.skip)) {
283                         fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
284                         goto raw_abort_;
285                 }
286                 if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
287                         if(decoder_session.verbose) fprintf(stderr, "\n");
288                         fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
289                         goto raw_abort_;
290                 }
291                 if(FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
292                         if(decoder_session.verbose) fprintf(stderr, "\n");
293                         fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
294                         goto raw_abort_;
295                 }
296         }
297         else {
298 #ifdef FLAC__HAS_OGG
299                 if(decoder_session.is_ogg) {
300                         if(!OggFLAC__stream_decoder_process_until_end_of_stream(decoder_session.decoder.stream)) {
301                                 if(decoder_session.verbose) fprintf(stderr, "\n");
302                                 fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", decoder_session.inbasefilename, OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream), FLAC__StreamDecoderStateString[OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream)]);
303                                 goto raw_abort_;
304                         }
305                         if(OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream) != FLAC__STREAM_DECODER_END_OF_STREAM) {
306                                 if(decoder_session.verbose) fprintf(stderr, "\n");
307                                 fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", decoder_session.inbasefilename, OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream), FLAC__StreamDecoderStateString[OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session.decoder.stream)]);
308                                 goto raw_abort_;
309                         }
310                 }
311                 else
312 #endif
313                 {
314                         if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
315                                 if(decoder_session.verbose) fprintf(stderr, "\n");
316                                 fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
317                                 goto raw_abort_;
318                         }
319                         if(FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder_session.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
320                                 if(decoder_session.verbose) fprintf(stderr, "\n");
321                                 fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", decoder_session.inbasefilename, FLAC__file_decoder_get_state(decoder_session.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session.decoder.file)]);
322                                 goto raw_abort_;
323                         }
324                 }
325         }
326
327 #ifdef FLAC__HAS_OGG
328         if(decoder_session.is_ogg) {
329                 if(decoder_session.decoder.stream) {
330                         OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
331                         md5_failure = false;
332                         print_stats(&decoder_session);
333                         OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
334                 }
335         }
336         else
337 #endif
338         {
339                 if(decoder_session.decoder.file) {
340                         md5_failure = !FLAC__file_decoder_finish(decoder_session.decoder.file);
341                         print_stats(&decoder_session);
342                         FLAC__file_decoder_delete(decoder_session.decoder.file);
343                 }
344         }
345         if(0 != decoder_session.fout && decoder_session.fout != stdout)
346                 fclose(decoder_session.fout);
347 #ifdef FLAC__HAS_OGG
348         if(decoder_session.is_ogg) {
349                 if(0 != decoder_session.fin && decoder_session.fin != stdin)
350                         fclose(decoder_session.fin);
351         }
352 #endif
353         if(analysis_mode)
354                 flac__analyze_finish(aopts);
355         if(md5_failure) {
356                 fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", decoder_session.inbasefilename);
357         }
358         else {
359                 if(decoder_session.verbose)
360                         fprintf(stderr, "\r%s: %s         \n", decoder_session.inbasefilename, decoder_session.test_only? "ok           ":analysis_mode?"done           ":"done");
361         }
362         return 0;
363 raw_abort_:
364 #ifdef FLAC__HAS_OGG
365         if(decoder_session.is_ogg) {
366                 if(decoder_session.decoder.stream) {
367                         OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
368                         OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
369                 }
370         }
371         else
372 #endif
373         {
374                 if(decoder_session.decoder.file) {
375                         FLAC__file_decoder_finish(decoder_session.decoder.file);
376                         FLAC__file_decoder_delete(decoder_session.decoder.file);
377                 }
378         }
379         if(0 != decoder_session.fout && decoder_session.fout != stdout) {
380                 fclose(decoder_session.fout);
381                 unlink(outfilename);
382         }
383 #ifdef FLAC__HAS_OGG
384         if(decoder_session.is_ogg) {
385                 if(0 != decoder_session.fin && decoder_session.fin != stdin)
386                         fclose(decoder_session.fin);
387         }
388 #endif
389         if(analysis_mode)
390                 flac__analyze_finish(aopts);
391         return 1;
392 }
393
394 FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool verbose, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, FLAC__bool analysis_mode, analysis_options aopts, FLAC_uint64 skip, const char *infilename, const char *outfilename)
395 {
396 #ifdef FLAC__HAS_OGG
397         d->is_ogg = options.common.is_ogg;
398 #endif
399
400         d->verbose = verbose;
401         d->is_wave_out = true;
402         d->continue_through_decode_errors = continue_through_decode_errors;
403         d->test_only = (0 == outfilename);
404         d->analysis_mode = analysis_mode;
405         d->aopts = aopts;
406         d->skip = common.skip;
407
408         d->inbasefilename = flac__file_get_basename(infilename);
409
410         d->samples_processed = 0;
411         d->frame_counter = 0;
412         d->abort_flag = false;
413
414         d->wave_chunk_size_fixup.needs_fixup = false;
415
416         d->decoder.flac.file = 0;
417 #ifdef FLAC__HAS_OGG
418         d->decoder.ogg.stream = 0;
419 #endif
420
421         d->fout = 0; /* initialized with an open file later if necessary */
422
423         FLAC__ASSERT(!(decoder_session.test_only && decoder_session.analysis_mode));
424
425         if(!d->test_only) {
426                 if(0 == strcmp(outfilename, "-")) {
427                         d->fout = file__get_binary_stdout();
428                 }
429                 else {
430                         if(0 == (d->fout = fopen(outfilename, "wb"))) {
431                                 fprintf(stderr, "%s: ERROR: can't open output file %s\n", d->inbasefilename, outfilename);
432                                 return 1;
433                         }
434                 }
435         }
436
437 #ifdef FLAC__HAS_OGG
438         if(d->is_ogg) {
439                 if (0 == strcmp(infilename, "-")) {
440                         d->fin = file__get_binary_stdin();
441                 } else {
442                         if (0 == (d->fin = fopen(infilename, "rb"))) {
443                                 fprintf(stderr, "%s: ERROR: can't open input file %s\n", d->inbasefilename, infilename);
444                                 if(0 != d->fout && d->fout != stdout)
445                                         fclose(d->fout);
446                                 return 1;
447                         }
448                 }
449         }
450 #endif
451
452         if(analysis_mode)
453                 flac__analyze_init(aopts);
454
455         return 0;
456 }
457
458 void DecoderSession_destroy(DecoderSession *d)
459 {
460 }
461
462 FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const char *infilename)
463 {
464         FLAC__uint32 test = 1;
465
466         is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
467
468 #ifdef FLAC__HAS_OGG
469         if(decoder_session->is_ogg) {
470                 decoder_session->decoder.stream = OggFLAC__stream_decoder_new();
471
472                 if(0 == decoder_session->decoder.stream) {
473                         fprintf(stderr, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename);
474                         return false;
475                 }
476
477                 OggFLAC__stream_decoder_set_read_callback(decoder_session->decoder.stream, read_callback);
478                 /*
479                  * The three ugly casts here are to 'downcast' the 'void *' argument of
480                  * the callback down to 'FLAC__StreamDecoder *'.  In C++ this would be
481                  * unnecessary but here the cast makes the C compiler happy.
482                  */
483                 OggFLAC__stream_decoder_set_write_callback(decoder_session->decoder.stream, (FLAC__StreamDecoderWriteStatus (*)(const OggFLAC__StreamDecoder *, const FLAC__Frame *, const FLAC__int32 * const [], void *))write_callback);
484                 OggFLAC__stream_decoder_set_metadata_callback(decoder_session->decoder.stream, (void (*)(const OggFLAC__StreamDecoder *, const FLAC__StreamMetadata *, void *))metadata_callback);
485                 OggFLAC__stream_decoder_set_error_callback(decoder_session->decoder.stream, (void (*)(const OggFLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
486                 OggFLAC__stream_decoder_set_client_data(decoder_session->decoder.stream, decoder_session);
487
488                 if(OggFLAC__stream_decoder_init(decoder_session->decoder.stream) != OggFLAC__STREAM_DECODER_OK) {
489                         fprintf(stderr, "%s: ERROR initializing decoder, state=%d:%s\n", decoder_session->inbasefilename, OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session->decoder.stream), FLAC__StreamDecoderStateString[OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder_session->decoder.stream)]);
490                         return false;
491                 }
492         }
493         else
494 #endif
495         {
496                 decoder_session->decoder.file = FLAC__file_decoder_new();
497
498                 if(0 == decoder_session->decoder.file) {
499                         fprintf(stderr, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename);
500                         return false;
501                 }
502
503                 FLAC__file_decoder_set_md5_checking(decoder_session->decoder.file, true);
504                 FLAC__file_decoder_set_filename(decoder_session->decoder.file, infilename);
505                 /*
506                  * The three ugly casts here are to 'downcast' the 'void *' argument of
507                  * the callback down to 'FLAC__FileDecoder *'.
508                  */
509                 FLAC__file_decoder_set_write_callback(decoder_session->decoder.file, (FLAC__StreamDecoderWriteStatus (*)(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 * const [], void *))write_callback);
510                 FLAC__file_decoder_set_metadata_callback(decoder_session->decoder.file, (void (*)(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *))metadata_callback);
511                 FLAC__file_decoder_set_error_callback(decoder_session->decoder.file, (void (*)(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
512                 FLAC__file_decoder_set_client_data(decoder_session->decoder.file, decoder_session);
513
514                 if(FLAC__file_decoder_init(decoder_session->decoder.file) != FLAC__FILE_DECODER_OK) {
515                         fprintf(stderr, "%s: ERROR initializing decoder, state=%d:%s\n", decoder_session->inbasefilename, FLAC__file_decoder_get_state(decoder_session->decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_session->decoder.file)]);
516                         return false;
517                 }
518         }
519
520         return true;
521 }
522
523 int DecoderSession_finish_ok(DecoderSession *d, int info_align_carry, int info_align_zero)
524 {
525 }
526
527 int DecoderSession_finish_error(DecoderSession *d)
528 {
529 }
530
531 FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val)
532 {
533         FLAC__byte *b = (FLAC__byte*)(&val);
534         if(is_big_endian_host_) {
535                 FLAC__byte tmp;
536                 tmp = b[1]; b[1] = b[0]; b[0] = tmp;
537         }
538         return fwrite(b, 1, 2, f) == 2;
539 }
540
541 FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val)
542 {
543         FLAC__byte *b = (FLAC__byte*)(&val);
544         if(is_big_endian_host_) {
545                 FLAC__byte tmp;
546                 tmp = b[3]; b[3] = b[0]; b[0] = tmp;
547                 tmp = b[2]; b[2] = b[1]; b[1] = tmp;
548         }
549         return fwrite(b, 1, 4, f) == 4;
550 }
551
552 FLAC__bool fixup_wave_chunk_size(const char *outfilename, unsigned riff_offset, unsigned data_offset, FLAC__uint32 data_size)
553 {
554         FILE *f = fopen(outfilename, "r+b");
555         if(0 == f) {
556                 fprintf(stderr, "ERROR, couldn't open file %s while fixing up WAVE chunk size\n", outfilename);
557                 return false;
558         }
559         if(fseek(f, riff_offset, SEEK_SET) < 0) {
560                 fprintf(stderr, "ERROR, couldn't seek in file %s while fixing up WAVE chunk size\n", outfilename);
561                 fclose(f);
562                 return false;
563         }
564         if(!write_little_endian_uint32(f, data_size + 36)) {
565                 fprintf(stderr, "ERROR, couldn't write size in file %s while fixing up WAVE chunk size\n", outfilename);
566                 fclose(f);
567                 return false;
568         }
569         if(fseek(f, data_offset, SEEK_SET) < 0) {
570                 fprintf(stderr, "ERROR, couldn't seek in file %s while fixing up WAVE chunk size\n", outfilename);
571                 fclose(f);
572                 return false;
573         }
574         if(!write_little_endian_uint32(f, data_size)) {
575                 fprintf(stderr, "ERROR, couldn't write size in file %s while fixing up WAVE chunk size\n", outfilename);
576                 fclose(f);
577                 return false;
578         }
579         fclose(f);
580         return true;
581 }
582
583 #ifdef FLAC__HAS_OGG
584 FLAC__StreamDecoderReadStatus read_callback(const OggFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
585 {
586         DecoderSession *decoder_session = (DecoderSession*)client_data;
587         FILE *fin = decoder_session->fin;
588         size_t bytes_read;
589
590         (void)decoder; /* avoid compiler warning */
591
592         if (decoder_session->abort_flag)
593                 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
594
595         if(feof(fin))
596                 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
597
598         bytes_read = fread(buffer, 1, *bytes, fin);
599
600         if(ferror(fin))
601                 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
602
603         *bytes = (unsigned)bytes_read;
604
605         return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
606 }
607 #endif
608
609 FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
610 {
611         DecoderSession *decoder_session = (DecoderSession*)client_data;
612         FILE *fout = decoder_session->fout;
613         unsigned bps = decoder_session->bps, channels = decoder_session->channels;
614         FLAC__bool is_big_endian = (decoder_session->is_wave_out? false : decoder_session->is_big_endian);
615         FLAC__bool is_unsigned_samples = (decoder_session->is_wave_out? bps<=8 : decoder_session->is_unsigned_samples);
616         unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
617         static FLAC__int8 s8buffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */
618         FLAC__uint8  *u8buffer  = (FLAC__uint8  *)s8buffer;
619         FLAC__int16  *s16buffer = (FLAC__int16  *)s8buffer;
620         FLAC__uint16 *u16buffer = (FLAC__uint16 *)s8buffer;
621         FLAC__int32  *s32buffer = (FLAC__int32  *)s8buffer;
622         FLAC__uint32 *u32buffer = (FLAC__uint32 *)s8buffer;
623
624         (void)decoder;
625
626         if(decoder_session->abort_flag)
627                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
628
629         decoder_session->samples_processed += wide_samples;
630         decoder_session->frame_counter++;
631
632         if(decoder_session->verbose && !(decoder_session->frame_counter & 0x7f))
633                 print_stats(decoder_session);
634
635         if(decoder_session->analysis_mode) {
636                 flac__analyze_frame(frame, decoder_session->frame_counter-1, decoder_session->aopts, fout);
637         }
638         else if(!decoder_session->test_only) {
639                 if(bps == 8) {
640                         if(is_unsigned_samples) {
641                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
642                                         for(channel = 0; channel < channels; channel++, sample++)
643                                                 u8buffer[sample] = (FLAC__uint8)(buffer[channel][wide_sample] + 0x80);
644                         }
645                         else {
646                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
647                                         for(channel = 0; channel < channels; channel++, sample++)
648                                                 s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_sample]);
649                         }
650                         if(fwrite(u8buffer, 1, sample, fout) != sample)
651                                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
652                 }
653                 else if(bps == 16) {
654                         if(is_unsigned_samples) {
655                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
656                                         for(channel = 0; channel < channels; channel++, sample++)
657                                                 u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000);
658                         }
659                         else {
660                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
661                                         for(channel = 0; channel < channels; channel++, sample++)
662                                                 s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]);
663                         }
664                         if(is_big_endian != is_big_endian_host_) {
665                                 unsigned char tmp;
666                                 const unsigned bytes = sample * 2;
667                                 for(byte = 0; byte < bytes; byte += 2) {
668                                         tmp = u8buffer[byte];
669                                         u8buffer[byte] = u8buffer[byte+1];
670                                         u8buffer[byte+1] = tmp;
671                                 }
672                         }
673                         if(fwrite(u16buffer, 2, sample, fout) != sample)
674                                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
675                 }
676                 else if(bps == 24) {
677                         if(is_unsigned_samples) {
678                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
679                                         for(channel = 0; channel < channels; channel++, sample++)
680                                                 u32buffer[sample] = buffer[channel][wide_sample] + 0x800000;
681                         }
682                         else {
683                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
684                                         for(channel = 0; channel < channels; channel++, sample++)
685                                                 s32buffer[sample] = buffer[channel][wide_sample];
686                         }
687                         if(is_big_endian != is_big_endian_host_) {
688                                 unsigned char tmp;
689                                 const unsigned bytes = sample * 4;
690                                 for(byte = 0; byte < bytes; byte += 4) {
691                                         tmp = u8buffer[byte];
692                                         u8buffer[byte] = u8buffer[byte+3];
693                                         u8buffer[byte+3] = tmp;
694                                         tmp = u8buffer[byte+1];
695                                         u8buffer[byte+1] = u8buffer[byte+2];
696                                         u8buffer[byte+2] = tmp;
697                                 }
698                         }
699                         if(is_big_endian) {
700                                 unsigned lbyte;
701                                 const unsigned bytes = sample * 4;
702                                 for(lbyte = byte = 0; byte < bytes; ) {
703                                         byte++;
704                                         u8buffer[lbyte++] = u8buffer[byte++];
705                                         u8buffer[lbyte++] = u8buffer[byte++];
706                                         u8buffer[lbyte++] = u8buffer[byte++];
707                                 }
708                         }
709                         else {
710                                 unsigned lbyte;
711                                 const unsigned bytes = sample * 4;
712                                 for(lbyte = byte = 0; byte < bytes; ) {
713                                         u8buffer[lbyte++] = u8buffer[byte++];
714                                         u8buffer[lbyte++] = u8buffer[byte++];
715                                         u8buffer[lbyte++] = u8buffer[byte++];
716                                         byte++;
717                                 }
718                         }
719                         if(fwrite(u8buffer, 3, sample, fout) != sample)
720                                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
721                 }
722                 else {
723                         FLAC__ASSERT(0);
724                 }
725         }
726         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
727 }
728
729 void metadata_callback(const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
730 {
731         DecoderSession *decoder_session = (DecoderSession*)client_data;
732         (void)decoder;
733         if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
734                 /* remember, metadata->data.decoder_session.total_samples can be 0, meaning 'unknown' */
735                 if(metadata->data.decoder_session.total_samples > 0 && decoder_session->skip >= metadata->data.decoder_session.total_samples) {
736                         fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", decoder_session->inbasefilename);
737                         decoder_session->abort_flag = true;
738                         return;
739                 }
740                 else if(metadata->data.decoder_session.total_samples == 0 && decoder_session->skip > 0) {
741                         fprintf(stderr, "%s: ERROR, can't skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
742                         decoder_session->abort_flag = true;
743                         return;
744                 }
745                 else
746                         decoder_session->total_samples = metadata->data.decoder_session.total_samples - decoder_session->skip;
747                 decoder_session->bps = metadata->data.decoder_session.bits_per_sample;
748                 decoder_session->channels = metadata->data.decoder_session.channels;
749                 decoder_session->sample_rate = metadata->data.decoder_session.sample_rate;
750
751                 if(decoder_session->bps != 8 && decoder_session->bps != 16 && decoder_session->bps != 24) {
752                         fprintf(stderr, "%s: ERROR: bits per sample is not 8/16/24\n", decoder_session->inbasefilename);
753                         decoder_session->abort_flag = true;
754                         return;
755                 }
756
757                 /* write the WAVE headers if necessary */
758                 if(!decoder_session->analysis_mode && !decoder_session->test_only && decoder_session->is_wave_out) {
759                         FLAC__uint64 data_size = decoder_session->total_samples * decoder_session->channels * ((decoder_session->bps+7)/8);
760                         if(decoder_session->total_samples == 0) {
761                                 if(decoder_session->fout == stdout) {
762                                         fprintf(stderr, "%s: WARNING, don't have accurate sample count available for WAVE header.\n", decoder_session->inbasefilename);
763                                         fprintf(stderr, "             Generated WAVE file will have a data chunk size of 0.  Try\n");
764                                         fprintf(stderr, "             decoding directly to a file instead.\n");
765                                 }
766                                 else {
767                                         decoder_session->wave_chunk_size_fixup.needs_fixup = true;
768                                 }
769                         }
770                         if(data_size >= 0xFFFFFFDC) {
771                                 fprintf(stderr, "%s: ERROR: stream is too big to fit in a single WAVE file chunk\n", decoder_session->inbasefilename);
772                                 decoder_session->abort_flag = true;
773                                 return;
774                         }
775                         if(fwrite("RIFF", 1, 4, decoder_session->fout) != 4) decoder_session->abort_flag = true;
776                         if(decoder_session->wave_chunk_size_fixup.needs_fixup)
777                                 decoder_session->wave_chunk_size_fixup.riff_offset = ftell(decoder_session->fout);
778                         if(!write_little_endian_uint32(decoder_session->fout, (FLAC__uint32)(data_size+36))) decoder_session->abort_flag = true; /* filesize-8 */
779                         if(fwrite("WAVEfmt ", 1, 8, decoder_session->fout) != 8) decoder_session->abort_flag = true;
780                         if(fwrite("\020\000\000\000", 1, 4, decoder_session->fout) != 4) decoder_session->abort_flag = true; /* chunk size = 16 */
781                         if(fwrite("\001\000", 1, 2, decoder_session->fout) != 2) decoder_session->abort_flag = true; /* compression code == 1 */
782                         if(!write_little_endian_uint16(decoder_session->fout, (FLAC__uint16)(decoder_session->channels))) decoder_session->abort_flag = true;
783                         if(!write_little_endian_uint32(decoder_session->fout, decoder_session->sample_rate)) decoder_session->abort_flag = true;
784                         if(!write_little_endian_uint32(decoder_session->fout, decoder_session->sample_rate * decoder_session->channels * ((decoder_session->bps+7) / 8))) decoder_session->abort_flag = true; /* @@@ or is it (sample_rate*channels*bps) / 8 ??? */
785                         if(!write_little_endian_uint16(decoder_session->fout, (FLAC__uint16)(decoder_session->channels * ((decoder_session->bps+7) / 8)))) decoder_session->abort_flag = true; /* block align */
786                         if(!write_little_endian_uint16(decoder_session->fout, (FLAC__uint16)(decoder_session->bps))) decoder_session->abort_flag = true; /* bits per sample */
787                         if(fwrite("data", 1, 4, decoder_session->fout) != 4) decoder_session->abort_flag = true;
788                         if(decoder_session->wave_chunk_size_fixup.needs_fixup)
789                                 decoder_session->wave_chunk_size_fixup.data_offset = ftell(decoder_session->fout);
790                         if(!write_little_endian_uint32(decoder_session->fout, (FLAC__uint32)data_size)) decoder_session->abort_flag = true; /* data size */
791                 }
792         }
793 }
794
795 void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
796 {
797         DecoderSession *decoder_session = (DecoderSession*)client_data;
798         (void)decoder;
799         fprintf(stderr, "%s: *** Got error code %d:%s\n", decoder_session->inbasefilename, status, FLAC__StreamDecoderErrorStatusString[status]);
800         if(!decoder_session->continue_through_decode_errors)
801                 decoder_session->abort_flag = true;
802 }
803
804 void print_stats(const DecoderSession *decoder_session)
805 {
806         if(decoder_session->verbose) {
807 #if defined _MSC_VER || defined __MINGW32__
808                 /* with VC++ you have to spoon feed it the casting */
809                 const double progress = (double)(FLAC__int64)decoder_session->samples_processed / (double)(FLAC__int64)decoder_session->total_samples * 100.0;
810 #else
811                 const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0;
812 #endif
813                 if(decoder_session->total_samples > 0) {
814                         fprintf(stderr, "\r%s: %s%u%% complete",
815                                 decoder_session->inbasefilename,
816                                 decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "",
817                                 (unsigned)floor(progress + 0.5)
818                         );
819                 }
820                 else {
821                         fprintf(stderr, "\r%s: %s %u samples",
822                                 decoder_session->inbasefilename,
823                                 decoder_session->test_only? "tested" : decoder_session->analysis_mode? "analyzed" : "wrote",
824                                 (unsigned)decoder_session->samples_processed
825                         );
826                 }
827         }
828 }