src/libFLAC/stream_decoder.c : Fix buffer read overflow.
[platform/upstream/flac.git] / examples / cpp / decode / file / main.cpp
1 /* example_cpp_decode_file - Simple FLAC file decoder using libFLAC
2  * Copyright (C) 2007-2009  Josh Coalson
3  * Copyright (C) 2011-2013  Xiph.Org Foundation
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 /*
21  * This example shows how to use libFLAC++ to decode a FLAC file to a WAVE
22  * file.  It only supports 16-bit stereo files.
23  *
24  * Complete API documentation can be found at:
25  *   http://flac.sourceforge.net/api/
26  */
27
28 #if HAVE_CONFIG_H
29 #  include <config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include "FLAC++/decoder.h"
36 #include "share/compat.h"
37
38 static FLAC__uint64 total_samples = 0;
39 static unsigned sample_rate = 0;
40 static unsigned channels = 0;
41 static unsigned bps = 0;
42
43 static bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
44 {
45         return
46                 fputc(x, f) != EOF &&
47                 fputc(x >> 8, f) != EOF
48         ;
49 }
50
51 static bool write_little_endian_int16(FILE *f, FLAC__int16 x)
52 {
53         return write_little_endian_uint16(f, (FLAC__uint16)x);
54 }
55
56 static bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
57 {
58         return
59                 fputc(x, f) != EOF &&
60                 fputc(x >> 8, f) != EOF &&
61                 fputc(x >> 16, f) != EOF &&
62                 fputc(x >> 24, f) != EOF
63         ;
64 }
65
66 class OurDecoder: public FLAC::Decoder::File {
67 public:
68         OurDecoder(FILE *f_): FLAC::Decoder::File(), f(f_) { }
69 protected:
70         FILE *f;
71
72         virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
73         virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
74         virtual void error_callback(::FLAC__StreamDecoderErrorStatus status);
75 };
76
77 int main(int argc, char *argv[])
78 {
79         bool ok = true;
80         FILE *fout;
81
82         if(argc != 3) {
83                 fprintf(stderr, "usage: %s infile.flac outfile.wav\n", argv[0]);
84                 return 1;
85         }
86
87         if((fout = fopen(argv[2], "wb")) == NULL) {
88                 fprintf(stderr, "ERROR: opening %s for output\n", argv[2]);
89                 return 1;
90         }
91
92         OurDecoder decoder(fout);
93
94         if(!decoder) {
95                 fprintf(stderr, "ERROR: allocating decoder\n");
96                 fclose(fout);
97                 return 1;
98         }
99
100         (void)decoder.set_md5_checking(true);
101
102         FLAC__StreamDecoderInitStatus init_status = decoder.init(argv[1]);
103         if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
104                 fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
105                 ok = false;
106         }
107
108         if(ok) {
109                 ok = decoder.process_until_end_of_stream();
110                 fprintf(stderr, "decoding: %s\n", ok? "succeeded" : "FAILED");
111                 fprintf(stderr, "   state: %s\n", decoder.get_state().resolved_as_cstring(decoder));
112         }
113
114         fclose(fout);
115
116         return 0;
117 }
118
119 ::FLAC__StreamDecoderWriteStatus OurDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
120 {
121         const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8));
122         size_t i;
123
124         if(total_samples == 0) {
125                 fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n");
126                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
127         }
128         if(channels != 2 || bps != 16) {
129                 fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
130                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
131         }
132
133         /* write WAVE header before we write the first frame */
134         if(frame->header.number.sample_number == 0) {
135                 if(
136                         fwrite("RIFF", 1, 4, f) < 4 ||
137                         !write_little_endian_uint32(f, total_size + 36) ||
138                         fwrite("WAVEfmt ", 1, 8, f) < 8 ||
139                         !write_little_endian_uint32(f, 16) ||
140                         !write_little_endian_uint16(f, 1) ||
141                         !write_little_endian_uint16(f, (FLAC__uint16)channels) ||
142                         !write_little_endian_uint32(f, sample_rate) ||
143                         !write_little_endian_uint32(f, sample_rate * channels * (bps/8)) ||
144                         !write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */
145                         !write_little_endian_uint16(f, (FLAC__uint16)bps) ||
146                         fwrite("data", 1, 4, f) < 4 ||
147                         !write_little_endian_uint32(f, total_size)
148                 ) {
149                         fprintf(stderr, "ERROR: write error\n");
150                         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
151                 }
152         }
153
154         /* write decoded PCM samples */
155         for(i = 0; i < frame->header.blocksize; i++) {
156                 if(
157                         !write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) ||  /* left channel */
158                         !write_little_endian_int16(f, (FLAC__int16)buffer[1][i])     /* right channel */
159                 ) {
160                         fprintf(stderr, "ERROR: write error\n");
161                         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
162                 }
163         }
164
165         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
166 }
167
168 void OurDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
169 {
170         /* print some stats */
171         if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
172                 /* save for later */
173                 total_samples = metadata->data.stream_info.total_samples;
174                 sample_rate = metadata->data.stream_info.sample_rate;
175                 channels = metadata->data.stream_info.channels;
176                 bps = metadata->data.stream_info.bits_per_sample;
177
178                 fprintf(stderr, "sample rate    : %u Hz\n", sample_rate);
179                 fprintf(stderr, "channels       : %u\n", channels);
180                 fprintf(stderr, "bits per sample: %u\n", bps);
181                 fprintf(stderr, "total samples  : %" PRIu64 "\n", total_samples);
182         }
183 }
184
185 void OurDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
186 {
187         fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
188 }