stream_decoder.c 85.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,2006  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
 */

Josh Coalson's avatar
Josh Coalson committed
32
33
34
35
#if HAVE_CONFIG_H
#  include <config.h>
#endif

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

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
	"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_MEMORY_ALLOCATION_ERROR",
155
	"FLAC__STREAM_DECODER_ALREADY_INITIALIZED",
156
	"FLAC__STREAM_DECODER_INVALID_CALLBACK",
Josh Coalson's avatar
Josh Coalson committed
157
158
159
	"FLAC__STREAM_DECODER_UNINITIALIZED"
};

160
FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
161
162
163
	"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
164
165
};

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

171
FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
172
173
	"FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
	"FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
174
175
	"FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH",
	"FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"
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
459
460
461
		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) {
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
			return false;
		}
462
463
464
465
466
467
468
469
470
		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;
}

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

485
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
486
{
Josh Coalson's avatar
Josh Coalson committed
487
488
489
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
490
	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
491
	/* double protection */
492
	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
493
		return false;
494
495
496
497
498
499
500
501
	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;
}

502
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
503
{
Josh Coalson's avatar
Josh Coalson committed
504
505
506
507
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != id);
508
509
510
511
512
513
514
515
516
	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
517
518
519
520
		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) {
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
			return false;
		}
521
522
523
524
525
526
527
528
529
		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;
}

530
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
531
{
Josh Coalson's avatar
Josh Coalson committed
532
533
534
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
535
536
537
538
539
540
541
	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;
}

542
FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
543
{
Josh Coalson's avatar
Josh Coalson committed
544
545
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
546
	return decoder->protected_->state;
547
548
}

Josh Coalson's avatar
Josh Coalson committed
549
550
551
552
553
FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
{
	return FLAC__StreamDecoderStateString[decoder->protected_->state];
}

554
FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
555
{
Josh Coalson's avatar
Josh Coalson committed
556
557
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
558
	return decoder->protected_->channels;
559
560
}

561
FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
562
{
Josh Coalson's avatar
Josh Coalson committed
563
564
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
565
	return decoder->protected_->channel_assignment;
566
567
}

568
FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
569
{
Josh Coalson's avatar
Josh Coalson committed
570
571
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
572
	return decoder->protected_->bits_per_sample;
573
574
}

575
FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
576
{
Josh Coalson's avatar
Josh Coalson committed
577
578
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
579
	return decoder->protected_->sample_rate;
580
581
}

582
FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
583
{
Josh Coalson's avatar
Josh Coalson committed
584
585
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
586
	return decoder->protected_->blocksize;
Josh Coalson's avatar
Josh Coalson committed
587
588
}

589
FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
590
{
Josh Coalson's avatar
Josh Coalson committed
591
592
593
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
594

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

	return true;
}

606
FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
607
{
Josh Coalson's avatar
Josh Coalson committed
608
609
610
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
611
612

	if(!FLAC__stream_decoder_flush(decoder)) {
613
		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
614
615
		return false;
	}
616
	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
Josh Coalson's avatar
Josh Coalson committed
617

618
	decoder->private_->samples_decoded = 0;
Josh Coalson's avatar
Josh Coalson committed
619

Josh Coalson's avatar
Josh Coalson committed
620
621
622
	return true;
}

623
FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
624
{
Josh Coalson's avatar
Josh Coalson committed
625
	FLAC__bool got_a_frame;
Josh Coalson's avatar
Josh Coalson committed
626
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
627
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
628
629

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

660
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
661
{
Josh Coalson's avatar
Josh Coalson committed
662
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
663
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
664
665

	while(1) {
666
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
667
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
Josh Coalson's avatar
Josh Coalson committed
668
				if(!find_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_READ_METADATA:
Josh Coalson's avatar
Josh Coalson committed
672
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
673
674
675
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
676
			case FLAC__STREAM_DECODER_READ_FRAME:
Josh Coalson's avatar
Josh Coalson committed
677
			case FLAC__STREAM_DECODER_END_OF_STREAM:
678
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
679
680
				return true;
			default:
681
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
682
				return false;
Josh Coalson's avatar
Josh Coalson committed
683
684
685
686
		}
	}
}

687
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
688
{
Josh Coalson's avatar
Josh Coalson committed
689
	FLAC__bool dummy;
Josh Coalson's avatar
Josh Coalson committed
690
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
691
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
692
693

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

752
753
754
755
756
757
/***********************************************************************
 *
 * Protected class methods
 *
 ***********************************************************************/

758
unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
759
{
Josh Coalson's avatar
Josh Coalson committed
760
	FLAC__ASSERT(0 != decoder);
761
	return FLAC__bitbuffer_get_input_bytes_unconsumed(decoder->private_->input);
Josh Coalson's avatar
Josh Coalson committed
762
763
}

764
765
766
767
768
769
/***********************************************************************
 *
 * Private class methods
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
770
void set_defaults_(FLAC__StreamDecoder *decoder)
771
772
773
774
775
776
777
778
779
780
781
782
{
	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
783
FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
Josh Coalson's avatar
Josh Coalson committed
784
785
{
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
786
	FLAC__int32 *tmp;
Josh Coalson's avatar
Josh Coalson committed
787

788
	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
Josh Coalson's avatar
Josh Coalson committed
789
790
		return true;

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

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

804
	for(i = 0; i < channels; i++) {
805
806
807
808
809
810
		/* 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.
		 */
811
		tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4));
Josh Coalson's avatar
Josh Coalson committed
812
		if(tmp == 0) {
813
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
814
815
			return false;
		}
816
		memset(tmp, 0, sizeof(FLAC__int32)*4);
817
		decoder->private_->output[i] = tmp + 4;
818

819
820
821
822
		/* 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])) {
823
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
824
825
			return false;
		}
Josh Coalson's avatar
Josh Coalson committed
826
827
	}

828
829
	decoder->private_->output_capacity = size;
	decoder->private_->output_channels = channels;
Josh Coalson's avatar
Josh Coalson committed
830
831
832
833

	return true;
}

Josh Coalson's avatar
Josh Coalson committed
834
FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
835
836
837
838
839
840
841
842
843
844
845
846
847
{
	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
848
FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
849
{
Josh Coalson's avatar
Josh Coalson committed
850
	FLAC__uint32 x;
Josh Coalson's avatar
Josh Coalson committed
851
	unsigned i, id;
Josh Coalson's avatar
Josh Coalson committed
852
	FLAC__bool first = true;
Josh Coalson's avatar
Josh Coalson committed
853

854
	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
Josh Coalson's avatar
Josh Coalson committed
855
856

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

			/* 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 */
888
889
				decoder->private_->lookahead = (FLAC__byte)x;
				decoder->private_->cached = true;
890
891
			}
			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
892
893
				decoder->private_->header_warmup[1] = (FLAC__byte)x;
				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
Josh Coalson's avatar
Josh Coalson committed
894
895
896
897
898
				return true;
			}
		}
		i = 0;
		if(first) {
899
			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
900
			first = false;
Josh Coalson's avatar
Josh Coalson committed
901
902
903
		}
	}

904
	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
Josh Coalson's avatar
Josh Coalson committed
905
906
907
	return true;
}

Josh Coalson's avatar
Josh Coalson committed
908
FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
909
{
910
911
	FLAC__bool is_last;
	FLAC__uint32 i, x, type, length;
Josh Coalson's avatar
Josh Coalson committed
912

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

915
	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
916
		return false; /* the read_callback_ sets the state for us */
917
918
	is_last = x? true : false;

919
	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
920
		return false; /* the read_callback_ sets the state for us */
921