code revamp finished
authorJosh Coalson <jcoalson@users.sourceforce.net>
Thu, 8 Aug 2002 22:47:40 +0000 (22:47 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Thu, 8 Aug 2002 22:47:40 +0000 (22:47 +0000)
src/flac/decode.c

index 5110a7b..0367b4b 100644 (file)
@@ -46,6 +46,7 @@ typedef struct {
        FLAC__uint64 skip;
 
        const char *inbasefilename;
+       const char *outfilename;
 
        FLAC__uint64 samples_processed;
        unsigned frame_counter;
@@ -88,10 +89,11 @@ static FLAC__bool is_big_endian_host_;
 /*
  * local routines
  */
-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);
-static void DecoderSession_destroy(DecoderSession *d);
-static FLAC__bool DecoderSession_init_decoder(const char *infilename, DecoderSession *decoder_session);
-static int DecoderSession_finish_ok(DecoderSession *d, int info_align_carry, int info_align_zero);
+static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, 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);
+static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
+static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, const char *infilename);
+static FLAC__bool DecoderSession_process(DecoderSession *d);
+static int DecoderSession_finish_ok(DecoderSession *d);
 static int DecoderSession_finish_error(DecoderSession *d);
 static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
 static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
@@ -107,6 +109,7 @@ static FLAC__StreamDecoderReadStatus read_callback(const OggFLAC__StreamDecoder
 static FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
 static void metadata_callback(const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
 static void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+static void print_error_with_state(const DecoderSession *d, const char *message);
 static void print_stats(const DecoderSession *decoder_session);
 
 
@@ -115,297 +118,55 @@ static void print_stats(const DecoderSession *decoder_session);
  */
 int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
 {
-       FLAC__bool md5_failure = false;
        DecoderSession decoder_session;
 
-       if(!DecoderSession_construct(options.common.verbose, /*is_wave_out=*/true, options.common.continue_through_decode_errors, analysis_mode, aopts, options.common.skip, infilename, outfilename))
+       if(!DecoderSession_construct(&decoder_session, options.common.is_ogg, options.common.verbose, /*is_wave_out=*/true, options.common.continue_through_decode_errors, analysis_mode, aopts, options.common.skip, infilename, outfilename))
                return 1;
 
        if(!DecoderSession_init_decoder(&decoder_session, infilename))
                return DecoderSession_finish_error(&decoder_session);
 
-       if(decoder_session.skip > 0) {
-#ifdef FLAC__HAS_OGG
-               if(decoder_session.is_ogg) { /*@@@ (move this check into main.c) */
-                       fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", decoder_session.inbasefilename);
-                       goto wav_abort_;
-               }
-#endif
-               if(!FLAC__file_decoder_process_until_end_of_metadata(decoder_session.decoder.file)) {
-                       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)]);
-                       goto wav_abort_;
-               }
-               if(decoder_session.abort_flag)
-                       goto wav_abort_;
-               if(!FLAC__file_decoder_seek_absolute(decoder_session.decoder.file, decoder_session.skip)) {
-                       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)]);
-                       goto wav_abort_;
-               }
-               if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
-                       if(decoder_session.verbose) fprintf(stderr, "\n");
-                       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)]);
-                       goto wav_abort_;
-               }
-               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) {
-                       if(decoder_session.verbose) fprintf(stderr, "\n");
-                       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)]);
-                       goto wav_abort_;
-               }
-       }
-       else {
-#ifdef FLAC__HAS_OGG
-               if(decoder_session.is_ogg) {
-                       if(!OggFLAC__stream_decoder_process_until_end_of_stream(decoder_session.decoder.stream)) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto wav_abort_;
-                       }
-                       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) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto wav_abort_;
-                       }
-               }
-               else
-#endif
-               {
-                       if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto wav_abort_;
-                       }
-                       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) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto wav_abort_;
-                       }
-               }
-       }
+       if(!DecoderSession_process(&decoder_session))
+               return DecoderSession_finish_error(&decoder_session);
 
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(decoder_session.decoder.stream) {
-                       OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
-                       md5_failure = false;
-                       print_stats(&decoder_session);
-                       OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
-               }
-       }
-       else
-#endif
-       {
-               if(decoder_session.decoder.file) {
-                       md5_failure = !FLAC__file_decoder_finish(decoder_session.decoder.file);
-                       print_stats(&decoder_session);
-                       FLAC__file_decoder_delete(decoder_session.decoder.file);
-               }
-       }
-       if(0 != decoder_session.fout && decoder_session.fout != stdout)
-               fclose(decoder_session.fout);
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(0 != decoder_session.fin && decoder_session.fin != stdin)
-                       fclose(decoder_session.fin);
-       }
-#endif
-       if(analysis_mode)
-               flac__analyze_finish(aopts);
-       if(decoder_session.wave_chunk_size_fixup.needs_fixup)
-               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))
-                       return 1;
-       if(md5_failure) {
-               fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", decoder_session.inbasefilename);
-       }
-       else {
-               if(decoder_session.verbose)
-                       fprintf(stderr, "\r%s: %s         \n", decoder_session.inbasefilename, decoder_session.test_only? "ok           ":analysis_mode?"done           ":"done");
-       }
-       return 0;
-wav_abort_:
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(decoder_session.decoder.stream) {
-                       OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
-                       OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
-               }
-       }
-       else
-#endif
-       {
-               if(decoder_session.decoder.file) {
-                       FLAC__file_decoder_finish(decoder_session.decoder.file);
-                       FLAC__file_decoder_delete(decoder_session.decoder.file);
-               }
-       }
-       if(0 != decoder_session.fout && decoder_session.fout != stdout) {
-               fclose(decoder_session.fout);
-               unlink(outfilename);
-       }
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(0 != decoder_session.fin && decoder_session.fin != stdin)
-                       fclose(decoder_session.fin);
-       }
-#endif
-       if(analysis_mode)
-               flac__analyze_finish(aopts);
-       return 1;
+       return DecoderSession_finish_ok(&decoder_session);
 }
 
 int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options)
 {
-       FLAC__bool md5_failure = false;
        DecoderSession decoder_session;
 
        decoder_session.is_big_endian = options.is_big_endian;
        decoder_session.is_unsigned_samples = options.is_unsigned_samples;
 
-       if(!DecoderSession_construct(options.common.verbose, /*is_wave_out=*/false, options.common.continue_through_decode_errors, analysis_mode, aopts, options.common.skip, infilename, outfilename))
+       if(!DecoderSession_construct(&decoder_session, options.common.is_ogg, options.common.verbose, /*is_wave_out=*/false, options.common.continue_through_decode_errors, analysis_mode, aopts, options.common.skip, infilename, outfilename))
                return 1;
 
        if(!DecoderSession_init_decoder(&decoder_session, infilename))
                return DecoderSession_finish_error(&decoder_session);
 
-       if(decoder_session.skip > 0) {
-#ifdef FLAC__HAS_OGG
-               if(decoder_session.is_ogg) { /*@@@ (move this check into main.c) */
-                       fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", decoder_session.inbasefilename);
-                       goto raw_abort_;
-               }
-#endif
-               if(!FLAC__file_decoder_process_until_end_of_metadata(decoder_session.decoder.file)) {
-                       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)]);
-                       goto raw_abort_;
-               }
-               if(decoder_session.abort_flag)
-                       goto raw_abort_;
-               if(!FLAC__file_decoder_seek_absolute(decoder_session.decoder.file, decoder_session.skip)) {
-                       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)]);
-                       goto raw_abort_;
-               }
-               if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
-                       if(decoder_session.verbose) fprintf(stderr, "\n");
-                       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)]);
-                       goto raw_abort_;
-               }
-               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) {
-                       if(decoder_session.verbose) fprintf(stderr, "\n");
-                       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)]);
-                       goto raw_abort_;
-               }
-       }
-       else {
-#ifdef FLAC__HAS_OGG
-               if(decoder_session.is_ogg) {
-                       if(!OggFLAC__stream_decoder_process_until_end_of_stream(decoder_session.decoder.stream)) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto raw_abort_;
-                       }
-                       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) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto raw_abort_;
-                       }
-               }
-               else
-#endif
-               {
-                       if(!FLAC__file_decoder_process_until_end_of_file(decoder_session.decoder.file)) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto raw_abort_;
-                       }
-                       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) {
-                               if(decoder_session.verbose) fprintf(stderr, "\n");
-                               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)]);
-                               goto raw_abort_;
-                       }
-               }
-       }
+       if(!DecoderSession_process(&decoder_session))
+               return DecoderSession_finish_error(&decoder_session);
 
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(decoder_session.decoder.stream) {
-                       OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
-                       md5_failure = false;
-                       print_stats(&decoder_session);
-                       OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
-               }
-       }
-       else
-#endif
-       {
-               if(decoder_session.decoder.file) {
-                       md5_failure = !FLAC__file_decoder_finish(decoder_session.decoder.file);
-                       print_stats(&decoder_session);
-                       FLAC__file_decoder_delete(decoder_session.decoder.file);
-               }
-       }
-       if(0 != decoder_session.fout && decoder_session.fout != stdout)
-               fclose(decoder_session.fout);
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(0 != decoder_session.fin && decoder_session.fin != stdin)
-                       fclose(decoder_session.fin);
-       }
-#endif
-       if(analysis_mode)
-               flac__analyze_finish(aopts);
-       if(md5_failure) {
-               fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", decoder_session.inbasefilename);
-       }
-       else {
-               if(decoder_session.verbose)
-                       fprintf(stderr, "\r%s: %s         \n", decoder_session.inbasefilename, decoder_session.test_only? "ok           ":analysis_mode?"done           ":"done");
-       }
-       return 0;
-raw_abort_:
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(decoder_session.decoder.stream) {
-                       OggFLAC__stream_decoder_finish(decoder_session.decoder.stream);
-                       OggFLAC__stream_decoder_delete(decoder_session.decoder.stream);
-               }
-       }
-       else
-#endif
-       {
-               if(decoder_session.decoder.file) {
-                       FLAC__file_decoder_finish(decoder_session.decoder.file);
-                       FLAC__file_decoder_delete(decoder_session.decoder.file);
-               }
-       }
-       if(0 != decoder_session.fout && decoder_session.fout != stdout) {
-               fclose(decoder_session.fout);
-               unlink(outfilename);
-       }
-#ifdef FLAC__HAS_OGG
-       if(decoder_session.is_ogg) {
-               if(0 != decoder_session.fin && decoder_session.fin != stdin)
-                       fclose(decoder_session.fin);
-       }
-#endif
-       if(analysis_mode)
-               flac__analyze_finish(aopts);
-       return 1;
+       return DecoderSession_finish_ok(&decoder_session);
 }
 
-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)
+FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, 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)
 {
 #ifdef FLAC__HAS_OGG
-       d->is_ogg = options.common.is_ogg;
+       d->is_ogg = is_ogg;
 #endif
 
        d->verbose = verbose;
-       d->is_wave_out = true;
+       d->is_wave_out = is_wave_out;
        d->continue_through_decode_errors = continue_through_decode_errors;
        d->test_only = (0 == outfilename);
        d->analysis_mode = analysis_mode;
        d->aopts = aopts;
-       d->skip = common.skip;
+       d->skip = skip;
 
        d->inbasefilename = flac__file_get_basename(infilename);
+       d->outfilename = outfilename;
 
        d->samples_processed = 0;
        d->frame_counter = 0;
@@ -418,9 +179,12 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool verbose, FLAC_
        d->decoder.ogg.stream = 0;
 #endif
 
+#ifdef FLAC__HAS_OGG
+       d->fin = 0;
+#endif
        d->fout = 0; /* initialized with an open file later if necessary */
 
-       FLAC__ASSERT(!(decoder_session.test_only && decoder_session.analysis_mode));
+       FLAC__ASSERT(!(d->test_only && d->analysis_mode));
 
        if(!d->test_only) {
                if(0 == strcmp(outfilename, "-")) {
@@ -429,7 +193,8 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool verbose, FLAC_
                else {
                        if(0 == (d->fout = fopen(outfilename, "wb"))) {
                                fprintf(stderr, "%s: ERROR: can't open output file %s\n", d->inbasefilename, outfilename);
-                               return 1;
+                               DecoderSession_destroy(d, /*error_occurred=*/true);
+                               return false;
                        }
                }
        }
@@ -441,9 +206,8 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool verbose, FLAC_
                } else {
                        if (0 == (d->fin = fopen(infilename, "rb"))) {
                                fprintf(stderr, "%s: ERROR: can't open input file %s\n", d->inbasefilename, infilename);
-                               if(0 != d->fout && d->fout != stdout)
-                                       fclose(d->fout);
-                               return 1;
+                               DecoderSession_destroy(d, /*error_occurred=*/true);
+                               return false;
                        }
                }
        }
@@ -452,11 +216,20 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool verbose, FLAC_
        if(analysis_mode)
                flac__analyze_init(aopts);
 
-       return 0;
+       return true;
 }
 
-void DecoderSession_destroy(DecoderSession *d)
+void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred)
 {
+       if(0 != d->fout && d->fout != stdout) {
+               fclose(d->fout);
+               if(error_occurred)
+                       unlink(d->outfilename);
+       }
+#ifdef FLAC__HAS_OGG
+       if(0 != d->fin && d->fin != stdin)
+               fclose(d->fin);
+#endif
 }
 
 FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const char *infilename)
@@ -467,52 +240,52 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const ch
 
 #ifdef FLAC__HAS_OGG
        if(decoder_session->is_ogg) {
-               decoder_session->decoder.stream = OggFLAC__stream_decoder_new();
+               decoder_session->decoder.ogg.stream = OggFLAC__stream_decoder_new();
 
-               if(0 == decoder_session->decoder.stream) {
+               if(0 == decoder_session->decoder.ogg.stream) {
                        fprintf(stderr, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename);
                        return false;
                }
 
-               OggFLAC__stream_decoder_set_read_callback(decoder_session->decoder.stream, read_callback);
+               OggFLAC__stream_decoder_set_read_callback(decoder_session->decoder.ogg.stream, read_callback);
                /*
                 * The three ugly casts here are to 'downcast' the 'void *' argument of
                 * the callback down to 'FLAC__StreamDecoder *'.  In C++ this would be
                 * unnecessary but here the cast makes the C compiler happy.
                 */
-               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);
-               OggFLAC__stream_decoder_set_metadata_callback(decoder_session->decoder.stream, (void (*)(const OggFLAC__StreamDecoder *, const FLAC__StreamMetadata *, void *))metadata_callback);
-               OggFLAC__stream_decoder_set_error_callback(decoder_session->decoder.stream, (void (*)(const OggFLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
-               OggFLAC__stream_decoder_set_client_data(decoder_session->decoder.stream, decoder_session);
+               OggFLAC__stream_decoder_set_write_callback(decoder_session->decoder.ogg.stream, (FLAC__StreamDecoderWriteStatus (*)(const OggFLAC__StreamDecoder *, const FLAC__Frame *, const FLAC__int32 * const [], void *))write_callback);
+               OggFLAC__stream_decoder_set_metadata_callback(decoder_session->decoder.ogg.stream, (void (*)(const OggFLAC__StreamDecoder *, const FLAC__StreamMetadata *, void *))metadata_callback);
+               OggFLAC__stream_decoder_set_error_callback(decoder_session->decoder.ogg.stream, (void (*)(const OggFLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
+               OggFLAC__stream_decoder_set_client_data(decoder_session->decoder.ogg.stream, decoder_session);
 
-               if(OggFLAC__stream_decoder_init(decoder_session->decoder.stream) != OggFLAC__STREAM_DECODER_OK) {
-                       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)]);
+               if(OggFLAC__stream_decoder_init(decoder_session->decoder.ogg.stream) != OggFLAC__STREAM_DECODER_OK) {
+                       print_error_with_state(decoder_session, "ERROR initializing decoder");
                        return false;
                }
        }
        else
 #endif
        {
-               decoder_session->decoder.file = FLAC__file_decoder_new();
+               decoder_session->decoder.flac.file = FLAC__file_decoder_new();
 
-               if(0 == decoder_session->decoder.file) {
+               if(0 == decoder_session->decoder.flac.file) {
                        fprintf(stderr, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename);
                        return false;
                }
 
-               FLAC__file_decoder_set_md5_checking(decoder_session->decoder.file, true);
-               FLAC__file_decoder_set_filename(decoder_session->decoder.file, infilename);
+               FLAC__file_decoder_set_md5_checking(decoder_session->decoder.flac.file, true);
+               FLAC__file_decoder_set_filename(decoder_session->decoder.flac.file, infilename);
                /*
                 * The three ugly casts here are to 'downcast' the 'void *' argument of
                 * the callback down to 'FLAC__FileDecoder *'.
                 */
-               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);
-               FLAC__file_decoder_set_metadata_callback(decoder_session->decoder.file, (void (*)(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *))metadata_callback);
-               FLAC__file_decoder_set_error_callback(decoder_session->decoder.file, (void (*)(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
-               FLAC__file_decoder_set_client_data(decoder_session->decoder.file, decoder_session);
+               FLAC__file_decoder_set_write_callback(decoder_session->decoder.flac.file, (FLAC__StreamDecoderWriteStatus (*)(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 * const [], void *))write_callback);
+               FLAC__file_decoder_set_metadata_callback(decoder_session->decoder.flac.file, (void (*)(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *))metadata_callback);
+               FLAC__file_decoder_set_error_callback(decoder_session->decoder.flac.file, (void (*)(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
+               FLAC__file_decoder_set_client_data(decoder_session->decoder.flac.file, decoder_session);
 
-               if(FLAC__file_decoder_init(decoder_session->decoder.file) != FLAC__FILE_DECODER_OK) {
-                       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)]);
+               if(FLAC__file_decoder_init(decoder_session->decoder.flac.file) != FLAC__FILE_DECODER_OK) {
+                       print_error_with_state(decoder_session, "ERROR initializing decoder");
                        return false;
                }
        }
@@ -520,12 +293,128 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const ch
        return true;
 }
 
-int DecoderSession_finish_ok(DecoderSession *d, int info_align_carry, int info_align_zero)
+FLAC__bool DecoderSession_process(DecoderSession *d)
 {
+       if(d->skip > 0) {
+#ifdef FLAC__HAS_OGG
+               if(d->is_ogg) { /*@@@ (move this check into main.c) */
+                       fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", d->inbasefilename);
+                       return false;
+               }
+#endif
+               if(!FLAC__file_decoder_process_until_end_of_metadata(d->decoder.flac.file)) {
+                       print_error_with_state(d, "ERROR while decoding metadata");
+                       return false;
+               }
+               if(d->abort_flag)
+                       return false;
+               if(!FLAC__file_decoder_seek_absolute(d->decoder.flac.file, d->skip)) {
+                       print_error_with_state(d, "ERROR seeking while skipping bytes");
+                       return false;
+               }
+               if(!FLAC__file_decoder_process_until_end_of_file(d->decoder.flac.file)) {
+                       if(d->verbose) fprintf(stderr, "\n");
+                       print_error_with_state(d, "ERROR while decoding frames");
+                       return false;
+               }
+               if(FLAC__file_decoder_get_state(d->decoder.flac.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(d->decoder.flac.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                       if(d->verbose) fprintf(stderr, "\n");
+                       print_error_with_state(d, "ERROR during decoding");
+                       return false;
+               }
+       }
+       else {
+#ifdef FLAC__HAS_OGG
+               if(d->is_ogg) {
+                       if(!OggFLAC__stream_decoder_process_until_end_of_stream(d->decoder.ogg.stream)) {
+                               if(d->verbose) fprintf(stderr, "\n");
+                               print_error_with_state(d, "ERROR while decoding data");
+                               return false;
+                       }
+                       if(OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(d->decoder.ogg.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(d->decoder.ogg.stream) != FLAC__STREAM_DECODER_END_OF_STREAM) {
+                               if(d->verbose) fprintf(stderr, "\n");
+                               print_error_with_state(d, "ERROR during decoding");
+                               return false;
+                       }
+               }
+               else
+#endif
+               {
+                       if(!FLAC__file_decoder_process_until_end_of_file(d->decoder.flac.file)) {
+                               if(d->verbose) fprintf(stderr, "\n");
+                               print_error_with_state(d, "ERROR while decoding data");
+                               return false;
+                       }
+                       if(FLAC__file_decoder_get_state(d->decoder.flac.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(d->decoder.flac.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                               if(d->verbose) fprintf(stderr, "\n");
+                               print_error_with_state(d, "ERROR during decoding");
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+int DecoderSession_finish_ok(DecoderSession *d)
+{
+       FLAC__bool md5_failure = false;
+
+#ifdef FLAC__HAS_OGG
+       if(d->is_ogg) {
+               if(d->decoder.ogg.stream) {
+                       OggFLAC__stream_decoder_finish(d->decoder.ogg.stream);
+                       md5_failure = false;
+                       print_stats(d);
+                       OggFLAC__stream_decoder_delete(d->decoder.ogg.stream);
+               }
+       }
+       else
+#endif
+       {
+               if(d->decoder.flac.file) {
+                       md5_failure = !FLAC__file_decoder_finish(d->decoder.flac.file);
+                       print_stats(d);
+                       FLAC__file_decoder_delete(d->decoder.flac.file);
+               }
+       }
+       if(d->analysis_mode)
+               flac__analyze_finish(d->aopts);
+       if(md5_failure) {
+               fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", d->inbasefilename);
+       }
+       else {
+               if(d->verbose)
+                       fprintf(stderr, "\r%s: %s         \n", d->inbasefilename, d->test_only? "ok           ":d->analysis_mode?"done           ":"done");
+       }
+       DecoderSession_destroy(d, /*error_occurred=*/false);
+       if(d->is_wave_out && d->wave_chunk_size_fixup.needs_fixup)
+               if(!fixup_wave_chunk_size(d->outfilename, d->wave_chunk_size_fixup.riff_offset, d->wave_chunk_size_fixup.data_offset, (FLAC__uint32)d->samples_processed))
+                       return 1;
+       return 0;
 }
 
 int DecoderSession_finish_error(DecoderSession *d)
 {
+#ifdef FLAC__HAS_OGG
+       if(d->is_ogg) {
+               if(d->decoder.ogg.stream) {
+                       OggFLAC__stream_decoder_finish(d->decoder.ogg.stream);
+                       OggFLAC__stream_decoder_delete(d->decoder.ogg.stream);
+               }
+       }
+       else
+#endif
+       {
+               if(d->decoder.flac.file) {
+                       FLAC__file_decoder_finish(d->decoder.flac.file);
+                       FLAC__file_decoder_delete(d->decoder.flac.file);
+               }
+       }
+       if(d->analysis_mode)
+               flac__analyze_finish(d->aopts);
+       DecoderSession_destroy(d, /*error_occurred=*/true);
+       return 1;
 }
 
 FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val)
@@ -629,7 +518,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__F
        decoder_session->samples_processed += wide_samples;
        decoder_session->frame_counter++;
 
-       if(decoder_session->verbose && !(decoder_session->frame_counter & 0x7f))
+       if(decoder_session->verbose && !(decoder_session->frame_counter & 0x3f))
                print_stats(decoder_session);
 
        if(decoder_session->analysis_mode) {
@@ -731,22 +620,22 @@ void metadata_callback(const void *decoder, const FLAC__StreamMetadata *metadata
        DecoderSession *decoder_session = (DecoderSession*)client_data;
        (void)decoder;
        if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
-               /* remember, metadata->data.decoder_session.total_samples can be 0, meaning 'unknown' */
-               if(metadata->data.decoder_session.total_samples > 0 && decoder_session->skip >= metadata->data.decoder_session.total_samples) {
+               /* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */
+               if(metadata->data.stream_info.total_samples > 0 && decoder_session->skip >= metadata->data.stream_info.total_samples) {
                        fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", decoder_session->inbasefilename);
                        decoder_session->abort_flag = true;
                        return;
                }
-               else if(metadata->data.decoder_session.total_samples == 0 && decoder_session->skip > 0) {
+               else if(metadata->data.stream_info.total_samples == 0 && decoder_session->skip > 0) {
                        fprintf(stderr, "%s: ERROR, can't skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
                        decoder_session->abort_flag = true;
                        return;
                }
                else
-                       decoder_session->total_samples = metadata->data.decoder_session.total_samples - decoder_session->skip;
-               decoder_session->bps = metadata->data.decoder_session.bits_per_sample;
-               decoder_session->channels = metadata->data.decoder_session.channels;
-               decoder_session->sample_rate = metadata->data.decoder_session.sample_rate;
+                       decoder_session->total_samples = metadata->data.stream_info.total_samples - decoder_session->skip;
+               decoder_session->bps = metadata->data.stream_info.bits_per_sample;
+               decoder_session->channels = metadata->data.stream_info.channels;
+               decoder_session->sample_rate = metadata->data.stream_info.sample_rate;
 
                if(decoder_session->bps != 8 && decoder_session->bps != 16 && decoder_session->bps != 24) {
                        fprintf(stderr, "%s: ERROR: bits per sample is not 8/16/24\n", decoder_session->inbasefilename);
@@ -801,6 +690,43 @@ void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status,
                decoder_session->abort_flag = true;
 }
 
+void print_error_with_state(const DecoderSession *d, const char *message)
+{
+       const int ilen = strlen(d->inbasefilename) + 1;
+
+       fprintf(stderr, "\n%s: %s\n", d->inbasefilename, message);
+
+#ifdef FLAC__HAS_OGG
+       if(d->is_ogg) {
+               const OggFLAC__StreamDecoderState osd_state = OggFLAC__stream_decoder_get_state(d->decoder.ogg.stream);
+               if(osd_state != OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR) {
+                       fprintf(stderr, "%*s state = %d:%s\n", ilen, "", (int)osd_state, OggFLAC__StreamDecoderStateString[osd_state]);
+               }
+               else {
+                       const FLAC__StreamDecoderState fsd_state = OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(d->decoder.ogg.stream);
+                       fprintf(stderr, "%*s state = %d:%s\n", ilen, "", (int)fsd_state, FLAC__StreamDecoderStateString[fsd_state]);
+               }
+       }
+       else
+#endif
+       {
+               const FLAC__FileDecoderState ffd_state = FLAC__file_decoder_get_state(d->decoder.flac.file);
+               if(ffd_state != FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR) {
+                       fprintf(stderr, "%*s state = %d:%s\n", ilen, "", (int)ffd_state, FLAC__FileDecoderStateString[ffd_state]);
+               }
+               else {
+                       const FLAC__SeekableStreamDecoderState fssd_state = FLAC__file_decoder_get_seekable_stream_decoder_state(d->decoder.flac.file);
+                       if(fssd_state != FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR) {
+                               fprintf(stderr, "%*s state = %d:%s\n", ilen, "", (int)fssd_state, FLAC__SeekableStreamDecoderStateString[fssd_state]);
+                       }
+                       else {
+                               const FLAC__StreamDecoderState fsd_state = FLAC__file_decoder_get_stream_decoder_state(d->decoder.flac.file);
+                               fprintf(stderr, "%*s state = %d:%s\n", ilen, "", (int)fsd_state, FLAC__StreamDecoderStateString[fsd_state]);
+                       }
+               }
+       }
+}
+
 void print_stats(const DecoderSession *decoder_session)
 {
        if(decoder_session->verbose) {