stream_decoder.c 84.7 KB
Newer Older
1
/* libFLAC - Free Lossless Audio Codec library
Josh Coalson's avatar
Josh Coalson committed
2
 * Copyright (C) 2000,2001,2002,2003,2004,2005  Josh Coalson
Josh Coalson's avatar
Josh Coalson committed
3
 *
4
5
6
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
Josh Coalson's avatar
Josh Coalson committed
7
 *
8
9
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
Josh Coalson's avatar
Josh Coalson committed
10
 *
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the Xiph.org Foundation nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Josh Coalson's avatar
Josh Coalson committed
30
31
32
33
 */

#include <stdio.h>
#include <stdlib.h> /* for malloc() */
Josh Coalson's avatar
Josh Coalson committed
34
#include <string.h> /* for memset/memcpy() */
35
#include "FLAC/assert.h"
36
#include "protected/stream_decoder.h"
Josh Coalson's avatar
Josh Coalson committed
37
#include "private/bitbuffer.h"
Josh Coalson's avatar
Josh Coalson committed
38
#include "private/bitmath.h"
39
#include "private/cpu.h"
Josh Coalson's avatar
Josh Coalson committed
40
41
#include "private/crc.h"
#include "private/fixed.h"
42
#include "private/format.h"
Josh Coalson's avatar
Josh Coalson committed
43
#include "private/lpc.h"
44
#include "private/memory.h"
Josh Coalson's avatar
Josh Coalson committed
45

Josh Coalson's avatar
Josh Coalson committed
46
47
48
49
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

50
51
52
53
54
#ifdef max
#undef max
#endif
#define max(a,b) ((a)>(b)?(a):(b))

55
56
57
58
59
60
61
/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
#ifdef _MSC_VER
#define FLAC__U64L(x) x
#else
#define FLAC__U64L(x) x##LLU
#endif

62
63
64
65
66
67
/***********************************************************************
 *
 * Private static data
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
68
static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
69
70
71
72
73
74
75

/***********************************************************************
 *
 * Private class method prototypes
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
76
77
78
79
80
static void set_defaults_(FLAC__StreamDecoder *decoder);
static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels);
static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
81
82
83
static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj);
84
static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
Josh Coalson's avatar
Josh Coalson committed
85
86
static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
87
static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
Josh Coalson's avatar
Josh Coalson committed
88
static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
89
90
91
92
93
static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
94
static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual);
Josh Coalson's avatar
Josh Coalson committed
95
static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
Josh Coalson's avatar
Josh Coalson committed
96
static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data);
97
98
99
100
101
102
103

/***********************************************************************
 *
 * Private class data
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
104
typedef struct FLAC__StreamDecoderPrivate {
Josh Coalson's avatar
Josh Coalson committed
105
106
107
108
	FLAC__StreamDecoderReadCallback read_callback;
	FLAC__StreamDecoderWriteCallback write_callback;
	FLAC__StreamDecoderMetadataCallback metadata_callback;
	FLAC__StreamDecoderErrorCallback error_callback;
109
	/* generic 32-bit datapath: */
Josh Coalson's avatar
Josh Coalson committed
110
	void (*local_lpc_restore_signal)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
111
	/* generic 64-bit datapath: */
112
	void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
113
	/* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
Josh Coalson's avatar
Josh Coalson committed
114
	void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
115
116
	/* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit), AND order <= 8: */
	void (*local_lpc_restore_signal_16bit_order8)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
Josh Coalson's avatar
Josh Coalson committed
117
	void *client_data;
118
	FLAC__BitBuffer *input;
Josh Coalson's avatar
Josh Coalson committed
119
	FLAC__int32 *output[FLAC__MAX_CHANNELS];
120
	FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */
121
	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
122
	unsigned output_capacity, output_channels;
Josh Coalson's avatar
Josh Coalson committed
123
	FLAC__uint32 last_frame_number;
124
	FLAC__uint32 last_block_size;
Josh Coalson's avatar
Josh Coalson committed
125
126
	FLAC__uint64 samples_decoded;
	FLAC__bool has_stream_info, has_seek_table;
127
128
	FLAC__StreamMetadata stream_info;
	FLAC__StreamMetadata seek_table;
129
	FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
130
131
	FLAC__byte *metadata_filter_ids;
	unsigned metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
132
	FLAC__Frame frame;
Josh Coalson's avatar
Josh Coalson committed
133
	FLAC__bool cached; /* true if there is a byte in lookahead */
134
	FLAC__CPUInfo cpuinfo;
Josh Coalson's avatar
Josh Coalson committed
135
136
	FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
	FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
137
138
	/* unaligned (original) pointers to allocated data */
	FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
Josh Coalson's avatar
Josh Coalson committed
139
140
} FLAC__StreamDecoderPrivate;

141
142
143
144
145
/***********************************************************************
 *
 * Public static class data
 *
 ***********************************************************************/
Josh Coalson's avatar
Josh Coalson committed
146

147
FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
Josh Coalson's avatar
Josh Coalson committed
148
149
150
151
152
153
154
155
	"FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
	"FLAC__STREAM_DECODER_READ_METADATA",
	"FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
	"FLAC__STREAM_DECODER_READ_FRAME",
	"FLAC__STREAM_DECODER_END_OF_STREAM",
	"FLAC__STREAM_DECODER_ABORTED",
	"FLAC__STREAM_DECODER_UNPARSEABLE_STREAM",
	"FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
156
	"FLAC__STREAM_DECODER_ALREADY_INITIALIZED",
157
	"FLAC__STREAM_DECODER_INVALID_CALLBACK",
Josh Coalson's avatar
Josh Coalson committed
158
159
160
	"FLAC__STREAM_DECODER_UNINITIALIZED"
};

161
FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
162
163
164
	"FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
	"FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
	"FLAC__STREAM_DECODER_READ_STATUS_ABORT"
Josh Coalson's avatar
Josh Coalson committed
165
166
};

167
FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
168
169
	"FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
	"FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
Josh Coalson's avatar
Josh Coalson committed
170
171
};

172
FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
173
174
175
	"FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
	"FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
	"FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH"
Josh Coalson's avatar
Josh Coalson committed
176
177
};

178
179
180
181
182
/***********************************************************************
 *
 * Class constructor/destructor
 *
 ***********************************************************************/
183
FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new()
Josh Coalson's avatar
Josh Coalson committed
184
{
185
	FLAC__StreamDecoder *decoder;
186
	unsigned i;
187
188
189

	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */

190
	decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder));
191
192
	if(decoder == 0) {
		return 0;
Josh Coalson's avatar
Josh Coalson committed
193
	}
Josh Coalson's avatar
Josh Coalson committed
194

195
	decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected));
196
	if(decoder->protected_ == 0) {
197
198
199
		free(decoder);
		return 0;
	}
Josh Coalson's avatar
Josh Coalson committed
200

201
	decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate));
202
203
	if(decoder->private_ == 0) {
		free(decoder->protected_);
204
205
206
		free(decoder);
		return 0;
	}
Josh Coalson's avatar
Josh Coalson committed
207

208
209
210
211
212
213
214
	decoder->private_->input = FLAC__bitbuffer_new();
	if(decoder->private_->input == 0) {
		free(decoder->private_);
		free(decoder->protected_);
		free(decoder);
		return 0;
	}
215

216
	decoder->private_->metadata_filter_ids_capacity = 16;
Josh Coalson's avatar
Josh Coalson committed
217
	if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
218
219
220
221
222
223
		FLAC__bitbuffer_delete(decoder->private_->input);
		free(decoder->private_);
		free(decoder->protected_);
		free(decoder);
		return 0;
	}
224

225
226
	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
		decoder->private_->output[i] = 0;
227
		decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
228
229
230
231
232
	}

	decoder->private_->output_capacity = 0;
	decoder->private_->output_channels = 0;
	decoder->private_->has_seek_table = false;
233
234
235

	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
236

Josh Coalson's avatar
Josh Coalson committed
237
	set_defaults_(decoder);
238

239
240
	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;

Josh Coalson's avatar
Josh Coalson committed
241
242
243
	return decoder;
}

244
FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
245
{
246
247
	unsigned i;

Josh Coalson's avatar
Josh Coalson committed
248
249
250
251
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->private_->input);
252

253
254
	FLAC__stream_decoder_finish(decoder);

Josh Coalson's avatar
Josh Coalson committed
255
	if(0 != decoder->private_->metadata_filter_ids)
256
257
		free(decoder->private_->metadata_filter_ids);

258
	FLAC__bitbuffer_delete(decoder->private_->input);
259

260
261
	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
262

263
264
	free(decoder->private_);
	free(decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
265
266
267
	free(decoder);
}

268
269
270
271
272
273
/***********************************************************************
 *
 * Public class methods
 *
 ***********************************************************************/

274
FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
275
{
Josh Coalson's avatar
Josh Coalson committed
276
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
277

278
279
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return decoder->protected_->state = FLAC__STREAM_DECODER_ALREADY_INITIALIZED;
Josh Coalson's avatar
Josh Coalson committed
280

281
282
	if(0 == decoder->private_->read_callback || 0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback)
		return decoder->protected_->state = FLAC__STREAM_DECODER_INVALID_CALLBACK;
Josh Coalson's avatar
Josh Coalson committed
283

284
285
	if(!FLAC__bitbuffer_init(decoder->private_->input))
		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
286

287
	decoder->private_->last_frame_number = 0;
288
	decoder->private_->last_block_size = 0;
289
290
291
	decoder->private_->samples_decoded = 0;
	decoder->private_->has_stream_info = false;
	decoder->private_->cached = false;
Josh Coalson's avatar
Josh Coalson committed
292

293
294
295
	/*
	 * get the CPU info and set the function pointers
	 */
296
	FLAC__cpu_info(&decoder->private_->cpuinfo);
297
	/* first default to the non-asm routines */
298
	decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
299
	decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
300
	decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
301
	decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal;
302
	/* now override with asm where appropriate */
303
#ifndef FLAC__NO_ASM
304
	if(decoder->private_->cpuinfo.use_asm) {
305
#ifdef FLAC__CPU_IA32
306
		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
307
#ifdef FLAC__HAS_NASM
308
309
310
		if(decoder->private_->cpuinfo.data.ia32.mmx) {
			decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx;
311
			decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32_mmx;
312
313
		}
		else {
314
315
			decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32;
316
			decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32;
317
		}
318
#endif
319
320
321
322
323
324
#elif defined FLAC__CPU_PPC
		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_PPC);
		if(decoder->private_->cpuinfo.data.ppc.altivec) {
			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ppc_altivec_16;
			decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8;
		}
325
#endif
326
	}
327
328
#endif

Josh Coalson's avatar
Josh Coalson committed
329
330
331
332
	if(!FLAC__stream_decoder_reset(decoder))
		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;

	return decoder->protected_->state;
Josh Coalson's avatar
Josh Coalson committed
333
334
}

335
FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
336
337
{
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
338
	FLAC__ASSERT(0 != decoder);
339
	if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
Josh Coalson's avatar
Josh Coalson committed
340
		return;
341
	if(0 != decoder->private_->seek_table.data.seek_table.points) {
342
343
		free(decoder->private_->seek_table.data.seek_table.points);
		decoder->private_->seek_table.data.seek_table.points = 0;
344
		decoder->private_->has_seek_table = false;
345
	}
346
	FLAC__bitbuffer_free(decoder->private_->input);
347
	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
348
349
350
351
352
353
		/* WATCHOUT:
		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
		 * output arrays have a buffer of up to 3 zeroes in front
		 * (at negative indices) for alignment purposes; we use 4
		 * to keep the data well-aligned.
		 */
Josh Coalson's avatar
Josh Coalson committed
354
		if(0 != decoder->private_->output[i]) {
355
356
			free(decoder->private_->output[i]-4);
			decoder->private_->output[i] = 0;
357
		}
358
359
360
		if(0 != decoder->private_->residual_unaligned[i]) {
			free(decoder->private_->residual_unaligned[i]);
			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
Josh Coalson's avatar
Josh Coalson committed
361
362
		}
	}
363
364
	decoder->private_->output_capacity = 0;
	decoder->private_->output_channels = 0;
365

Josh Coalson's avatar
Josh Coalson committed
366
	set_defaults_(decoder);
367

368
	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
369
370
}

371
FLAC_API FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value)
372
{
Josh Coalson's avatar
Josh Coalson committed
373
374
375
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
376
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
377
		return false;
378
	decoder->private_->read_callback = value;
379
380
381
	return true;
}

382
FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value)
383
{
Josh Coalson's avatar
Josh Coalson committed
384
385
386
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
387
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
388
		return false;
389
	decoder->private_->write_callback = value;
390
391
392
	return true;
}

393
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value)
394
{
Josh Coalson's avatar
Josh Coalson committed
395
396
397
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
398
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
399
		return false;
400
	decoder->private_->metadata_callback = value;
401
402
403
	return true;
}

404
FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value)
405
{
Josh Coalson's avatar
Josh Coalson committed
406
407
408
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
409
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
410
		return false;
411
	decoder->private_->error_callback = value;
412
413
414
	return true;
}

415
FLAC_API FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value)
416
{
Josh Coalson's avatar
Josh Coalson committed
417
418
419
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
420
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
421
		return false;
422
	decoder->private_->client_data = value;
423
424
425
	return true;
}

426
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
427
{
Josh Coalson's avatar
Josh Coalson committed
428
429
430
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
431
	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
432
	/* double protection */
433
	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
434
		return false;
435
436
437
438
439
440
441
442
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;
	decoder->private_->metadata_filter[type] = true;
	if(type == FLAC__METADATA_TYPE_APPLICATION)
		decoder->private_->metadata_filter_ids_count = 0;
	return true;
}

443
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
444
{
Josh Coalson's avatar
Josh Coalson committed
445
446
447
448
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != id);
449
450
451
452
453
454
455
456
457
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;

	if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
		return true;

	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);

	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
Josh Coalson's avatar
Josh Coalson committed
458
		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2)))
459
460
461
462
463
464
465
466
467
468
			return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
		decoder->private_->metadata_filter_ids_capacity *= 2;
	}

	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
	decoder->private_->metadata_filter_ids_count++;

	return true;
}

469
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
470
{
471
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
472
473
474
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
475
476
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;
477
478
	for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
		decoder->private_->metadata_filter[i] = true;
479
480
481
482
	decoder->private_->metadata_filter_ids_count = 0;
	return true;
}

483
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
484
{
Josh Coalson's avatar
Josh Coalson committed
485
486
487
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
488
	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
489
	/* double protection */
490
	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
491
		return false;
492
493
494
495
496
497
498
499
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;
	decoder->private_->metadata_filter[type] = false;
	if(type == FLAC__METADATA_TYPE_APPLICATION)
		decoder->private_->metadata_filter_ids_count = 0;
	return true;
}

500
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
501
{
Josh Coalson's avatar
Josh Coalson committed
502
503
504
505
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != id);
506
507
508
509
510
511
512
513
514
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;

	if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
		return true;

	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);

	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
Josh Coalson's avatar
Josh Coalson committed
515
		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2)))
516
517
518
519
520
521
522
523
524
525
			return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
		decoder->private_->metadata_filter_ids_capacity *= 2;
	}

	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
	decoder->private_->metadata_filter_ids_count++;

	return true;
}

526
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
527
{
Josh Coalson's avatar
Josh Coalson committed
528
529
530
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
531
532
533
534
535
536
537
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;
	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
	decoder->private_->metadata_filter_ids_count = 0;
	return true;
}

538
FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
539
{
Josh Coalson's avatar
Josh Coalson committed
540
541
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
542
	return decoder->protected_->state;
543
544
}

Josh Coalson's avatar
Josh Coalson committed
545
546
547
548
549
FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
{
	return FLAC__StreamDecoderStateString[decoder->protected_->state];
}

550
FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
551
{
Josh Coalson's avatar
Josh Coalson committed
552
553
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
554
	return decoder->protected_->channels;
555
556
}

557
FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
558
{
Josh Coalson's avatar
Josh Coalson committed
559
560
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
561
	return decoder->protected_->channel_assignment;
562
563
}

564
FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
565
{
Josh Coalson's avatar
Josh Coalson committed
566
567
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
568
	return decoder->protected_->bits_per_sample;
569
570
}

571
FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
572
{
Josh Coalson's avatar
Josh Coalson committed
573
574
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
575
	return decoder->protected_->sample_rate;
576
577
}

578
FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
579
{
Josh Coalson's avatar
Josh Coalson committed
580
581
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
582
	return decoder->protected_->blocksize;
Josh Coalson's avatar
Josh Coalson committed
583
584
}

585
FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
586
{
Josh Coalson's avatar
Josh Coalson committed
587
588
589
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
590

591
	if(!FLAC__bitbuffer_clear(decoder->private_->input)) {
592
		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
593
594
		return false;
	}
595
596
	decoder->private_->last_frame_number = 0;
	decoder->private_->last_block_size = 0;
597
	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
Josh Coalson's avatar
Josh Coalson committed
598
599
600
601

	return true;
}

602
FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
603
{
Josh Coalson's avatar
Josh Coalson committed
604
605
606
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
607
608

	if(!FLAC__stream_decoder_flush(decoder)) {
609
		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
610
611
		return false;
	}
612
	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
Josh Coalson's avatar
Josh Coalson committed
613

614
	decoder->private_->samples_decoded = 0;
Josh Coalson's avatar
Josh Coalson committed
615

Josh Coalson's avatar
Josh Coalson committed
616
617
618
	return true;
}

619
FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
620
{
Josh Coalson's avatar
Josh Coalson committed
621
	FLAC__bool got_a_frame;
Josh Coalson's avatar
Josh Coalson committed
622
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
623
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
624
625

	while(1) {
626
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
627
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
Josh Coalson's avatar
Josh Coalson committed
628
				if(!find_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
629
630
631
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_METADATA:
Josh Coalson's avatar
Josh Coalson committed
632
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
633
					return false; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
634
635
				else
					return true;
Josh Coalson's avatar
Josh Coalson committed
636
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
Josh Coalson's avatar
Josh Coalson committed
637
				if(!frame_sync_(decoder))
Josh Coalson's avatar
Josh Coalson committed
638
639
640
					return true; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_FRAME:
641
				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
Josh Coalson's avatar
Josh Coalson committed
642
					return false; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
643
644
				if(got_a_frame)
					return true; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
645
646
				break;
			case FLAC__STREAM_DECODER_END_OF_STREAM:
647
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
648
649
				return true;
			default:
650
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
651
				return false;
Josh Coalson's avatar
Josh Coalson committed
652
653
654
655
		}
	}
}

656
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
657
{
Josh Coalson's avatar
Josh Coalson committed
658
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
659
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
660
661

	while(1) {
662
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
663
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
Josh Coalson's avatar
Josh Coalson committed
664
				if(!find_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
665
666
667
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_METADATA:
Josh Coalson's avatar
Josh Coalson committed
668
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
669
670
671
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
672
			case FLAC__STREAM_DECODER_READ_FRAME:
Josh Coalson's avatar
Josh Coalson committed
673
			case FLAC__STREAM_DECODER_END_OF_STREAM:
674
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
675
676
				return true;
			default:
677
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
678
				return false;
Josh Coalson's avatar
Josh Coalson committed
679
680
681
682
		}
	}
}

683
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
684
{
Josh Coalson's avatar
Josh Coalson committed
685
	FLAC__bool dummy;
Josh Coalson's avatar
Josh Coalson committed
686
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
687
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
688
689

	while(1) {
690
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
691
692
693
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
				if(!find_metadata_(decoder))
					return false; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
694
				break;
Josh Coalson's avatar
Josh Coalson committed
695
696
			case FLAC__STREAM_DECODER_READ_METADATA:
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
697
698
699
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
Josh Coalson's avatar
Josh Coalson committed
700
				if(!frame_sync_(decoder))
Josh Coalson's avatar
Josh Coalson committed
701
702
703
					return true; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_FRAME:
704
				if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
Josh Coalson's avatar
Josh Coalson committed
705
706
707
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_END_OF_STREAM:
708
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
709
710
				return true;
			default:
711
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
712
				return false;
Josh Coalson's avatar
Josh Coalson committed
713
714
715
716
		}
	}
}

717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
{
	FLAC__bool got_a_frame;
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);

	while(1) {
		switch(decoder->protected_->state) {
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
			case FLAC__STREAM_DECODER_READ_METADATA:
				return false; /* above function sets the status for us */
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
				if(!frame_sync_(decoder))
					return true; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_FRAME:
				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
					return false; /* above function sets the status for us */
				if(got_a_frame)
					return true; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_END_OF_STREAM:
			case FLAC__STREAM_DECODER_ABORTED:
				return true;
			default:
				FLAC__ASSERT(0);
				return false;
		}
	}
}

748
749
750
751
752
753
/***********************************************************************
 *
 * Protected class methods
 *
 ***********************************************************************/

754
unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
755
{
Josh Coalson's avatar
Josh Coalson committed
756
	FLAC__ASSERT(0 != decoder);
757
	return FLAC__bitbuffer_get_input_bytes_unconsumed(decoder->private_->input);
Josh Coalson's avatar
Josh Coalson committed
758
759
}

760
761
762
763
764
765
/***********************************************************************
 *
 * Private class methods
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
766
void set_defaults_(FLAC__StreamDecoder *decoder)
767
768
769
770
771
772
773
774
775
776
777
778
{
	decoder->private_->read_callback = 0;
	decoder->private_->write_callback = 0;
	decoder->private_->metadata_callback = 0;
	decoder->private_->error_callback = 0;
	decoder->private_->client_data = 0;

	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
	decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true;
	decoder->private_->metadata_filter_ids_count = 0;
}

Josh Coalson's avatar
Josh Coalson committed
779
FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
Josh Coalson's avatar
Josh Coalson committed
780
781
{
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
782
	FLAC__int32 *tmp;
Josh Coalson's avatar
Josh Coalson committed
783

784
	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
Josh Coalson's avatar
Josh Coalson committed
785
786
		return true;

Josh Coalson's avatar
Josh Coalson committed
787
	/* simply using realloc() is not practical because the number of channels may change mid-stream */
788

Josh Coalson's avatar
Josh Coalson committed
789
	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
Josh Coalson's avatar
Josh Coalson committed
790
		if(0 != decoder->private_->output[i]) {
791
			free(decoder->private_->output[i]-4);
792
			decoder->private_->output[i] = 0;
Josh Coalson's avatar
Josh Coalson committed
793
		}
794
795
796
		if(0 != decoder->private_->residual_unaligned[i]) {
			free(decoder->private_->residual_unaligned[i]);
			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
797
		}
Josh Coalson's avatar
Josh Coalson committed
798
799
	}

800
	for(i = 0; i < channels; i++) {
801
802
803
804
805
806
		/* WATCHOUT:
		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
		 * output arrays have a buffer of up to 3 zeroes in front
		 * (at negative indices) for alignment purposes; we use 4
		 * to keep the data well-aligned.
		 */
807
		tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4));
Josh Coalson's avatar
Josh Coalson committed
808
		if(tmp == 0) {
809
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
810
811
			return false;
		}
812
		memset(tmp, 0, sizeof(FLAC__int32)*4);
813
		decoder->private_->output[i] = tmp + 4;
814

815
816
817
818
		/* WATCHOUT:
		 * minimum of quadword alignment for PPC vector optimizations is REQUIRED:
		 */
		if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
819
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
820
821
			return false;
		}
Josh Coalson's avatar
Josh Coalson committed
822
823
	}

824
825
	decoder->private_->output_capacity = size;
	decoder->private_->output_channels = channels;
Josh Coalson's avatar
Josh Coalson committed
826
827
828
829

	return true;
}

Josh Coalson's avatar
Josh Coalson committed
830
FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
831
832
833
834
835
836
837
838
839
840
841
842
843
{
	unsigned i;

	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);

	for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
		if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
			return true;

	return false;
}

Josh Coalson's avatar
Josh Coalson committed
844
FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
845
{
Josh Coalson's avatar
Josh Coalson committed
846
	FLAC__uint32 x;
Josh Coalson's avatar
Josh Coalson committed
847
	unsigned i, id;
Josh Coalson's avatar
Josh Coalson committed
848
	FLAC__bool first = true;
Josh Coalson's avatar
Josh Coalson committed
849

850
	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
Josh Coalson's avatar
Josh Coalson committed
851
852

	for(i = id = 0; i < 4; ) {
853
854
855
		if(decoder->private_->cached) {
			x = (FLAC__uint32)decoder->private_->lookahead;
			decoder->private_->cached = false;
856
857
		}
		else {
858
			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
859
860
				return false; /* the read_callback_ sets the state for us */
		}
Josh Coalson's avatar
Josh Coalson committed
861
		if(x == FLAC__STREAM_SYNC_STRING[i]) {
862
			first = true;
Josh Coalson's avatar
Josh Coalson committed
863
864
865
866
867
868
869
870
			i++;
			id = 0;
			continue;
		}
		if(x == ID3V2_TAG_[id]) {
			id++;
			i = 0;
			if(id == 3) {
Josh Coalson's avatar
Josh Coalson committed
871
				if(!skip_id3v2_tag_(decoder))
Josh Coalson's avatar
Josh Coalson committed
872
873
874
875
876
					return false; /* the read_callback_ sets the state for us */
			}
			continue;
		}
		if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
877
			decoder->private_->header_warmup[0] = (FLAC__byte)x;
878
			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
Josh Coalson's avatar
Josh Coalson committed
879
				return false; /* the read_callback_ sets the state for us */
880
881
882
883

			/* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
			/* else we have to check if the second byte is the end of a sync code */
			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
884
885
				decoder->private_->lookahead = (FLAC__byte)x;
				decoder->private_->cached = true;
886
887
			}
			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
888
889
				decoder->private_->header_warmup[1] = (FLAC__byte)x;
				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
Josh Coalson's avatar
Josh Coalson committed
890
891
892
893
894
				return true;
			}
		}
		i = 0;
		if(first) {
895
			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
896
			first = false;
Josh Coalson's avatar
Josh Coalson committed
897
898
899
		}
	}

900
	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
Josh Coalson's avatar
Josh Coalson committed
901
902
903
	return true;
}

Josh Coalson's avatar
Josh Coalson committed
904
FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
905
{
906
907
	FLAC__bool is_last;
	FLAC__uint32 i, x, type, length;
Josh Coalson's avatar
Josh Coalson committed
908

909
	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
Josh Coalson's avatar
Josh Coalson committed
910

911
	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN, read_callback_, decoder))
Josh Coalson's avatar
Josh Coalson committed
912
		return false; /* the read_callback_ sets the state for us */
913
914
	is_last = x? true : false;

915
	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN, read_callback_, decoder))
Josh Coalson's avatar
Josh Coalson committed
916
		return false; /* the read_callback_ sets the state for us */
917

918
	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN, read_callback_, decoder))
Josh Coalson's avatar
Josh Coalson committed
919
		return false; /* the read_callback_ sets the state for us */