Change order of flac_LDADD libs so it works with mingw.
[platform/upstream/flac.git] / src / flac / decode.c
index d98cf6a..4aa70d3 100644 (file)
@@ -1,5 +1,5 @@
 /* flac - Command-line FLAC encoder/decoder
- * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007,2008  Josh Coalson
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007,2008,2009  Josh Coalson
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #  include <config.h>
 #endif
 
-#if defined _WIN32 && !defined __CYGWIN__
-/* where MSVC puts unlink() */
-# include <io.h>
-#else
-# include <unistd.h>
-#endif
-#if defined _MSC_VER || defined __MINGW32__
-#include <sys/types.h> /* for off_t */
-#if _MSC_VER <= 1600 /* @@@ [2G limit] */
-#define fseeko fseek
-#define ftello ftell
-#endif
-#endif
 #include <errno.h>
 #include <math.h> /* for floor() */
 #include <stdio.h> /* for FILE etc. */
@@ -40,6 +27,7 @@
 #include "FLAC/all.h"
 #include "share/grabbag.h"
 #include "share/replaygain_synthesis.h"
+#include "share/compat.h"
 #include "decode.h"
 
 typedef struct {
@@ -77,6 +65,7 @@ typedef struct {
        FLAC__bool abort_flag;
        FLAC__bool aborting_due_to_until; /* true if we intentionally abort decoding prematurely because we hit the --until point */
        FLAC__bool aborting_due_to_unparseable; /* true if we abort decoding because we hit an unparseable frame */
+       FLAC__bool error_callback_suppress_messages; /* turn on to prevent repeating messages from the error callback */
 
        FLAC__bool iff_headers_need_fixup;
 
@@ -116,7 +105,7 @@ static int DecoderSession_finish_ok(DecoderSession *d);
 static int DecoderSession_finish_error(DecoderSession *d);
 static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
 static FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples);
-static FLAC__bool write_riff_wave_fmt_chunk(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask);
+static FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask);
 static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, unsigned bps, unsigned channels, unsigned sample_rate);
 static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
 static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
@@ -142,6 +131,7 @@ int flac__decode_file(const char *infilename, const char *outfilename, FLAC__boo
 
        FLAC__ASSERT(
                options.format == FORMAT_WAVE ||
+               options.format == FORMAT_WAVE64 ||
                options.format == FORMAT_RF64 ||
                options.format == FORMAT_AIFF ||
                options.format == FORMAT_AIFF_C ||
@@ -227,6 +217,7 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__
        d->abort_flag = false;
        d->aborting_due_to_until = false;
        d->aborting_due_to_unparseable = false;
+       d->error_callback_suppress_messages = false;
 
        d->iff_headers_need_fixup = false;
 
@@ -402,13 +393,28 @@ FLAC__bool DecoderSession_process(DecoderSession *d)
                return false;
        }
 
-       if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW && ((d->total_samples * d->channels * ((d->bps+7)/8)) & 1)) {
-               if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) {
-                       print_error_with_state(d, d->format == FORMAT_WAVE || d->format == FORMAT_RF64?
-                               "ERROR writing pad byte to WAVE data chunk" :
-                               "ERROR writing pad byte to AIFF SSND chunk"
-                       );
-                       return false;
+       /* write padding bytes for alignment if necessary */
+       if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+               const FLAC__uint64 data_size = d->total_samples * d->channels * ((d->bps+7)/8);
+               unsigned padding;
+               if(d->format != FORMAT_WAVE64) {
+                       padding = (unsigned)(data_size & 1);
+               }
+               else {
+                       /* 8-byte alignment for Wave64 */
+                       padding = (8 - (unsigned)(data_size & 7)) & 7;
+               }
+               for( ; padding > 0; --padding) {
+                       if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) {
+                               print_error_with_state(
+                                       d,
+                                       d->format == FORMAT_WAVE?   "ERROR writing pad byte to WAVE data chunk" :
+                                       d->format == FORMAT_WAVE64? "ERROR writing pad bytes to WAVE64 data chunk" :
+                                       d->format == FORMAT_RF64?   "ERROR writing pad byte to RF64 data chunk" :
+                                       "ERROR writing pad byte to AIFF SSND chunk"
+                               );
+                               return false;
+                       }
                }
        }
 
@@ -518,18 +524,37 @@ FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec,
 FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples)
 {
        const FileFormat format = decoder_session->format;
-       const char *fmt_desc = format==FORMAT_WAVE? "WAVE" : format==FORMAT_RF64? "RF64" : "AIFF";
-       const FLAC__bool is_wavish = format == FORMAT_WAVE || format == FORMAT_RF64;
-       const FLAC__bool is_waveformatextensible = is_wavish && (decoder_session->channel_mask == 2 || decoder_session->channel_mask > 3 || decoder_session->bps%8 || decoder_session->channels > 2);
+       const char *fmt_desc =
+               format==FORMAT_WAVE? "WAVE" :
+               format==FORMAT_WAVE64? "Wave64" :
+               format==FORMAT_RF64? "RF64" :
+               "AIFF";
+       const FLAC__bool is_waveformatextensible =
+               (format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) &&
+               (
+                       decoder_session->channel_mask == 2 ||
+                       decoder_session->channel_mask > 3 ||
+                       decoder_session->bps%8 ||
+                       decoder_session->channels > 2
+               );
        const FLAC__uint64 data_size = samples * decoder_session->channels * ((decoder_session->bps+7)/8);
-       const FLAC__uint64 aligned_data_size = data_size & 1? (data_size+1) : data_size;
+       const FLAC__uint64 aligned_data_size =
+               format == FORMAT_WAVE64?
+                       (data_size+7) & (~(FLAC__uint64)7) :
+                       (data_size+1) & (~(FLAC__uint64)1);
 
        FLAC__uint64 iff_size;
        unsigned foreign_metadata_size = 0; /* size of all non-audio non-fmt/COMM foreign metadata chunks */
        foreign_metadata_t *fm = decoder_session->foreign_metadata;
        size_t i;
 
-       FLAC__ASSERT(flac__utils_format_is_iff(format));
+       FLAC__ASSERT(
+               format == FORMAT_WAVE ||
+               format == FORMAT_WAVE64 ||
+               format == FORMAT_RF64 ||
+               format == FORMAT_AIFF ||
+               format == FORMAT_AIFF_C
+       );
 
        if(samples == 0) {
                if(f == stdout) {
@@ -548,7 +573,7 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin
                FLAC__ASSERT(fm->format_block);
                FLAC__ASSERT(fm->audio_block);
                FLAC__ASSERT(fm->format_block < fm->audio_block);
-               /* calc foreign metadata size; for RIFF/AIFF we always skip the first chunk, ds64 chunk, format chunk, and sound chunk since we write our own */
+               /* calc foreign metadata size; we always skip the first chunk, ds64 chunk, format chunk, and sound chunk since we write our own */
                for(i = format==FORMAT_RF64?2:1; i < fm->num_blocks; i++) {
                        if(i != fm->format_block && i != fm->audio_block)
                                foreign_metadata_size += fm->blocks[i].size;
@@ -557,36 +582,60 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin
 
        if(samples == 0)
                iff_size = 0;
-       else if(is_wavish)
-               iff_size = (is_waveformatextensible?60:36) + (format==FORMAT_RF64?36:0) + foreign_metadata_size + aligned_data_size;
-       else
-               /* @@@@@@ can ssnd_offset_size be odd and hence screw up our alignment logic? */
-               iff_size = 46 + foreign_metadata_size + aligned_data_size + (fm? fm->ssnd_offset_size : 0);
-
-       if(format != FORMAT_RF64 && iff_size >= 0xFFFFFFF4) {
+       else if(format == FORMAT_WAVE || format == FORMAT_RF64)
+               /* 4 for WAVE form bytes */
+               /* +{36,0} for ds64 chunk */
+               /* +8+{40,16} for fmt chunk header and body */
+               /* +8 for data chunk header */
+               iff_size = 4 + (format==FORMAT_RF64?36:0) + 8+(is_waveformatextensible?40:16) + 8 + foreign_metadata_size + aligned_data_size;
+       else if(format == FORMAT_WAVE64)
+               /* 16+8 for RIFF GUID and size field */
+               /* +16 for WAVE GUID */
+               /* +16+8+{40,16} for fmt chunk header (GUID and size field) and body */
+               /* +16+8 for data chunk header (GUID and size field) */
+               iff_size = 16+8 + 16 + 16+8+(is_waveformatextensible?40:16) + 16+8 + foreign_metadata_size + aligned_data_size;
+       else /* AIFF */
+               iff_size = 46 + foreign_metadata_size + aligned_data_size;
+
+       if(format != FORMAT_WAVE64 && format != FORMAT_RF64 && iff_size >= 0xFFFFFFF4) {
                flac__utils_printf(stderr, 1, "%s: ERROR: stream is too big to fit in a single %s file\n", decoder_session->inbasefilename, fmt_desc);
                return false;
        }
 
-       if(is_wavish) {
-               if(format == FORMAT_RF64) {
-                       if(flac__utils_fwrite("RF64", 1, 4, f) != 4)
-                               return false;
-
-                       if(!write_little_endian_uint32(f, 0xffffffff))
-                               return false;
-               }
-               else {
-                       if(flac__utils_fwrite("RIFF", 1, 4, f) != 4)
-                               return false;
-
-                       if(!write_little_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */
+       if(format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) {
+               /* RIFF header */
+               switch(format) {
+                       case FORMAT_WAVE:
+                               if(flac__utils_fwrite("RIFF", 1, 4, f) != 4)
+                                       return false;
+                               if(!write_little_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */
+                                       return false;
+                               if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+                                       return false;
+                               break;
+                       case FORMAT_WAVE64:
+                               /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+                               if(flac__utils_fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xD6\xA5\x28\xDB\x04\xC1\x00\x00", 1, 16, f) != 16)
+                                       return false;
+                               if(!write_little_endian_uint64(f, iff_size))
+                                       return false;
+                               /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+                               if(flac__utils_fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+                                       return false;
+                               break;
+                       case FORMAT_RF64:
+                               if(flac__utils_fwrite("RF64", 1, 4, f) != 4)
+                                       return false;
+                               if(!write_little_endian_uint32(f, 0xffffffff))
+                                       return false;
+                               if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+                                       return false;
+                               break;
+                       default:
                                return false;
                }
 
-               if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
-                       return false;
-
+               /* ds64 chunk for RF64 */
                if(format == FORMAT_RF64) {
                        if(flac__utils_fwrite("ds64", 1, 4, f) != 4)
                                return false;
@@ -619,7 +668,22 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin
                        }
                }
 
-               if(!write_riff_wave_fmt_chunk(f, is_waveformatextensible, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, decoder_session->channel_mask))
+               if(format != FORMAT_WAVE64) {
+                       if(flac__utils_fwrite("fmt ", 1, 4, f) != 4)
+                               return false;
+                       if(!write_little_endian_uint32(f, is_waveformatextensible? 40 : 16)) /* chunk size */
+                               return false;
+               }
+               else { /* Wave64 */
+                       /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+                       if(flac__utils_fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+                               return false;
+                       /* chunk size (+16+8 for GUID and size fields) */
+                       if(!write_little_endian_uint64(f, 16+8+(is_waveformatextensible?40:16)))
+                               return false;
+               }
+
+               if(!write_riff_wave_fmt_chunk_body(f, is_waveformatextensible, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, decoder_session->channel_mask))
                        return false;
 
                decoder_session->fm_offset2 = ftello(f);
@@ -634,17 +698,24 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin
                        }
                }
 
-               if(flac__utils_fwrite("data", 1, 4, f) != 4)
-                       return false;
-
-               if(!write_little_endian_uint32(f, format==FORMAT_RF64? 0xffffffff : (FLAC__uint32)data_size))
-                       return false;
+               if(format != FORMAT_WAVE64) {
+                       if(flac__utils_fwrite("data", 1, 4, f) != 4)
+                               return false;
+                       if(!write_little_endian_uint32(f, format==FORMAT_RF64? 0xffffffff : (FLAC__uint32)data_size))
+                               return false;
+               }
+               else { /* Wave64 */
+                       /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+                       if(flac__utils_fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+                               return false;
+                       /* +16+8 for GUID and size fields */
+                       if(!write_little_endian_uint64(f, 16+8 + data_size))
+                               return false;
+               }
 
                decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
        }
        else {
-               FLAC__uint32 ssnd_offset_size = (fm? fm->ssnd_offset_size : 0);
-
                if(flac__utils_fwrite("FORM", 1, 4, f) != 4)
                        return false;
 
@@ -684,37 +755,23 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin
                if(flac__utils_fwrite("SSND", 1, 4, f) != 4)
                        return false;
 
-               if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8 + ssnd_offset_size)) /* data size */
+               if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8)) /* data size */
                        return false;
 
-               if(!write_big_endian_uint32(f, ssnd_offset_size))
+               if(!write_big_endian_uint32(f, 0/*offset_size*/))
                        return false;
 
                if(!write_big_endian_uint32(f, 0/*block_size*/))
                        return false;
 
-               if(ssnd_offset_size) {
-                       /* seek forward to {allocate} or {skip over already-written} SSND offset */
-                       if(fseeko(f, ssnd_offset_size, SEEK_CUR) < 0) {
-                               flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping \"SSND\" offset\n", decoder_session->inbasefilename);
-                               return false;
-                       }
-               }
-
                decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
        }
 
        return true;
 }
 
-FLAC__bool write_riff_wave_fmt_chunk(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask)
+FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask)
 {
-       if(flac__utils_fwrite("fmt ", 1, 4, f) != 4)
-               return false;
-
-       if(!write_little_endian_uint32(f, is_waveformatextensible? 40 : 16)) /* chunk size */
-               return false;
-
        if(!write_little_endian_uint16(f, (FLAC__uint16)(is_waveformatextensible? 65534 : 1))) /* compression code */
                return false;
 
@@ -864,7 +921,11 @@ FLAC__bool write_sane_extended(FILE *f, unsigned val)
 
 FLAC__bool fixup_iff_headers(DecoderSession *d)
 {
-       const char *fmt_desc = d->format==FORMAT_WAVE? "WAVE" : d->format==FORMAT_RF64? "RF64" : "AIFF";
+       const char *fmt_desc =
+               d->format==FORMAT_WAVE? "WAVE" :
+               d->format==FORMAT_WAVE64? "Wave64" :
+               d->format==FORMAT_RF64? "RF64" :
+               "AIFF";
        FILE *f = fopen(d->outfilename, "r+b"); /* stream is positioned at beginning of file */
 
        if(0 == f) {
@@ -886,15 +947,15 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder
        DecoderSession *decoder_session = (DecoderSession*)client_data;
        FILE *fout = decoder_session->fout;
        const unsigned bps = frame->header.bits_per_sample, channels = frame->header.channels;
-       const unsigned shift = (decoder_session->format != FORMAT_RAW && (bps%8)? 8-(bps%8): 0);
+       const unsigned shift = (decoder_session->format != FORMAT_RAW && (bps%8))? 8-(bps%8): 0;
        FLAC__bool is_big_endian = (
                decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? true : (
-               decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_RF64 ? false :
+               decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? false :
                decoder_session->is_big_endian
        ));
        FLAC__bool is_unsigned_samples = (
                decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? false : (
-               decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_RF64 ? bps<=8 :
+               decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? bps<=8 :
                decoder_session->is_unsigned_samples
        ));
        unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
@@ -1286,11 +1347,26 @@ void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderError
 {
        DecoderSession *decoder_session = (DecoderSession*)client_data;
        (void)decoder;
-       flac__utils_printf(stderr, 1, "%s: *** Got error code %d:%s\n", decoder_session->inbasefilename, status, FLAC__StreamDecoderErrorStatusString[status]);
+       if(!decoder_session->error_callback_suppress_messages)
+               flac__utils_printf(stderr, 1, "%s: *** Got error code %d:%s\n", decoder_session->inbasefilename, status, FLAC__StreamDecoderErrorStatusString[status]);
        if(!decoder_session->continue_through_decode_errors) {
-               decoder_session->abort_flag = true;
-               if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+               /* if we got a sync error while looking for metadata, either it's not a FLAC file (more likely) or the file is corrupted */
+               if(
+                       !decoder_session->error_callback_suppress_messages &&
+                       status == FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC &&
+                       FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+               ) {
+                       flac__utils_printf(stderr, 1,
+                               "\n"
+                               "The input file is either not a FLAC file or is corrupted.  If you are\n"
+                               "convinced it is a FLAC file, you can rerun the same command and add the\n"
+                               "-F parameter to try and recover as much as possible from the file.\n"
+                       );
+                       decoder_session->error_callback_suppress_messages = true;
+               }
+               else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
                        decoder_session->aborting_due_to_unparseable = true;
+               decoder_session->abort_flag = true;
        }
 }
 
@@ -1338,6 +1414,7 @@ void print_error_with_state(const DecoderSession *d, const char *message)
 
 void print_stats(const DecoderSession *decoder_session)
 {
+       static int count = 0;
        if(flac__utils_verbosity_ >= 2) {
 #if defined _MSC_VER || defined __MINGW32__
                /* with MSVC you have to spoon feed it the casting */
@@ -1346,7 +1423,13 @@ void print_stats(const DecoderSession *decoder_session)
                const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0;
 #endif
                if(decoder_session->total_samples > 0) {
-                       fprintf(stderr, "\r%s: %s%u%% complete",
+                       while (count > 0 && count--)
+                               fprintf(stderr, "\b");
+
+                       if ((unsigned)floor(progress + 0.5) == 100)
+                               return;
+
+                       count = fprintf(stderr, "%s: %s%u%% complete",
                                decoder_session->inbasefilename,
                                decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "",
                                (unsigned)floor(progress + 0.5)