stream_decoder.c 72 KB
Newer Older
1
/* libFLAC - Free Lossless Audio Codec library
2
 * Copyright (C) 2000,2001,2002  Josh Coalson
Josh Coalson's avatar
Josh Coalson committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 */

#include <stdio.h>
#include <stdlib.h> /* for malloc() */
Josh Coalson's avatar
Josh Coalson committed
22
#include <string.h> /* for memset/memcpy() */
23
#include "FLAC/assert.h"
24
#include "protected/stream_decoder.h"
Josh Coalson's avatar
Josh Coalson committed
25
#include "private/bitbuffer.h"
Josh Coalson's avatar
Josh Coalson committed
26
#include "private/bitmath.h"
27
#include "private/cpu.h"
Josh Coalson's avatar
Josh Coalson committed
28
29
#include "private/crc.h"
#include "private/fixed.h"
30
#include "private/format.h"
Josh Coalson's avatar
Josh Coalson committed
31
32
#include "private/lpc.h"

33
34
35
36
37
#ifdef max
#undef max
#endif
#define max(a,b) ((a)>(b)?(a):(b))

38
39
40
41
42
43
/***********************************************************************
 *
 * Private static data
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
44
static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
45
46
47
48
49
50
51

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

Josh Coalson's avatar
Josh Coalson committed
52
53
54
55
56
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);
57
58
59
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);
Josh Coalson's avatar
Josh Coalson committed
60
61
62
63
64
65
66
67
68
static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame);
static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps);
static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps);
static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order);
static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order);
static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps);
69
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
70
static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
Josh Coalson's avatar
Josh Coalson committed
71
static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data);
72
73
74
75
76
77
78

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

Josh Coalson's avatar
Josh Coalson committed
79
typedef struct FLAC__StreamDecoderPrivate {
Josh Coalson's avatar
Josh Coalson committed
80
81
82
83
	FLAC__StreamDecoderReadCallback read_callback;
	FLAC__StreamDecoderWriteCallback write_callback;
	FLAC__StreamDecoderMetadataCallback metadata_callback;
	FLAC__StreamDecoderErrorCallback error_callback;
Josh Coalson's avatar
Josh Coalson committed
84
	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[]);
85
	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[]);
Josh Coalson's avatar
Josh Coalson committed
86
	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[]);
Josh Coalson's avatar
Josh Coalson committed
87
	void *client_data;
88
	FLAC__BitBuffer *input;
Josh Coalson's avatar
Josh Coalson committed
89
90
	FLAC__int32 *output[FLAC__MAX_CHANNELS];
	FLAC__int32 *residual[FLAC__MAX_CHANNELS];
91
	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
92
	unsigned output_capacity, output_channels;
Josh Coalson's avatar
Josh Coalson committed
93
94
95
	FLAC__uint32 last_frame_number;
	FLAC__uint64 samples_decoded;
	FLAC__bool has_stream_info, has_seek_table;
96
97
	FLAC__StreamMetadata stream_info;
	FLAC__StreamMetadata seek_table;
98
99
100
	FLAC__bool metadata_filter[FLAC__METADATA_TYPE_VORBIS_COMMENT+1];
	FLAC__byte *metadata_filter_ids;
	unsigned metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
101
	FLAC__Frame frame;
Josh Coalson's avatar
Josh Coalson committed
102
	FLAC__bool cached; /* true if there is a byte in lookahead */
103
	FLAC__CPUInfo cpuinfo;
Josh Coalson's avatar
Josh Coalson committed
104
105
	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 */
Josh Coalson's avatar
Josh Coalson committed
106
107
} FLAC__StreamDecoderPrivate;

108
109
110
111
112
/***********************************************************************
 *
 * Public static class data
 *
 ***********************************************************************/
Josh Coalson's avatar
Josh Coalson committed
113

114
FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
Josh Coalson's avatar
Josh Coalson committed
115
116
117
118
119
120
121
122
	"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",
123
	"FLAC__STREAM_DECODER_ALREADY_INITIALIZED",
124
	"FLAC__STREAM_DECODER_INVALID_CALLBACK",
Josh Coalson's avatar
Josh Coalson committed
125
126
127
	"FLAC__STREAM_DECODER_UNINITIALIZED"
};

128
FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
129
130
131
	"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
132
133
};

134
FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
135
136
	"FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
	"FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
Josh Coalson's avatar
Josh Coalson committed
137
138
};

139
FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
140
141
142
	"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
143
144
};

145
146
147
148
149
/***********************************************************************
 *
 * Class constructor/destructor
 *
 ***********************************************************************/
150
FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new()
Josh Coalson's avatar
Josh Coalson committed
151
{
152
	FLAC__StreamDecoder *decoder;
153
	unsigned i;
154
155
156

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

157
	decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder));
158
159
	if(decoder == 0) {
		return 0;
Josh Coalson's avatar
Josh Coalson committed
160
	}
Josh Coalson's avatar
Josh Coalson committed
161

162
	decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected));
163
	if(decoder->protected_ == 0) {
164
165
166
		free(decoder);
		return 0;
	}
Josh Coalson's avatar
Josh Coalson committed
167

168
	decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate));
169
170
	if(decoder->private_ == 0) {
		free(decoder->protected_);
171
172
173
		free(decoder);
		return 0;
	}
Josh Coalson's avatar
Josh Coalson committed
174

175
176
177
178
179
180
181
	decoder->private_->input = FLAC__bitbuffer_new();
	if(decoder->private_->input == 0) {
		free(decoder->private_);
		free(decoder->protected_);
		free(decoder);
		return 0;
	}
182

183
	decoder->private_->metadata_filter_ids_capacity = 16;
Josh Coalson's avatar
Josh Coalson committed
184
	if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
185
186
187
188
189
190
		FLAC__bitbuffer_delete(decoder->private_->input);
		free(decoder->private_);
		free(decoder->protected_);
		free(decoder);
		return 0;
	}
191

192
193
194
195
196
197
198
199
	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
		decoder->private_->output[i] = 0;
		decoder->private_->residual[i] = 0;
	}

	decoder->private_->output_capacity = 0;
	decoder->private_->output_channels = 0;
	decoder->private_->has_seek_table = false;
200
201
202

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

Josh Coalson's avatar
Josh Coalson committed
204
	set_defaults_(decoder);
205

206
207
	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;

Josh Coalson's avatar
Josh Coalson committed
208
209
210
	return decoder;
}

211
FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
212
{
213
214
	unsigned i;

Josh Coalson's avatar
Josh Coalson committed
215
216
217
218
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->private_->input);
219

220
221
	FLAC__stream_decoder_finish(decoder);

Josh Coalson's avatar
Josh Coalson committed
222
	if(0 != decoder->private_->metadata_filter_ids)
223
224
		free(decoder->private_->metadata_filter_ids);

225
	FLAC__bitbuffer_delete(decoder->private_->input);
226

227
228
	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
229

230
231
	free(decoder->private_);
	free(decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
232
233
234
	free(decoder);
}

235
236
237
238
239
240
/***********************************************************************
 *
 * Public class methods
 *
 ***********************************************************************/

241
FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
242
{
Josh Coalson's avatar
Josh Coalson committed
243
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
244

245
246
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return decoder->protected_->state = FLAC__STREAM_DECODER_ALREADY_INITIALIZED;
Josh Coalson's avatar
Josh Coalson committed
247

248
249
	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
250

251
252
	if(!FLAC__bitbuffer_init(decoder->private_->input))
		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
253

254
255
256
257
	decoder->private_->last_frame_number = 0;
	decoder->private_->samples_decoded = 0;
	decoder->private_->has_stream_info = false;
	decoder->private_->cached = false;
Josh Coalson's avatar
Josh Coalson committed
258

259
260
261
	/*
	 * get the CPU info and set the function pointers
	 */
262
	FLAC__cpu_info(&decoder->private_->cpuinfo);
263
	/* first default to the non-asm routines */
264
	decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
265
	decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
266
	decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
267
	/* now override with asm where appropriate */
268
#ifndef FLAC__NO_ASM
269
	if(decoder->private_->cpuinfo.use_asm) {
270
#ifdef FLAC__CPU_IA32
271
		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
272
#ifdef FLAC__HAS_NASM
273
274
275
		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;
276
277
		}
		else {
278
279
			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;
280
		}
281
#endif
282
#endif
283
	}
284
285
#endif

Josh Coalson's avatar
Josh Coalson committed
286
287
288
289
	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
290
291
}

292
FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
293
294
{
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
295
	FLAC__ASSERT(0 != decoder);
296
	if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
Josh Coalson's avatar
Josh Coalson committed
297
		return;
298
	if(decoder->private_->has_seek_table) {
Josh Coalson's avatar
Josh Coalson committed
299
		FLAC__ASSERT(0 != decoder->private_->seek_table.data.seek_table.points);
300
301
		free(decoder->private_->seek_table.data.seek_table.points);
		decoder->private_->seek_table.data.seek_table.points = 0;
302
		decoder->private_->has_seek_table = false;
303
	}
304
	FLAC__bitbuffer_free(decoder->private_->input);
305
	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
306
307
308
309
310
311
		/* 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
312
		if(0 != decoder->private_->output[i]) {
313
314
			free(decoder->private_->output[i]-4);
			decoder->private_->output[i] = 0;
315
		}
Josh Coalson's avatar
Josh Coalson committed
316
		if(0 != decoder->private_->residual[i]) {
317
318
			free(decoder->private_->residual[i]);
			decoder->private_->residual[i] = 0;
Josh Coalson's avatar
Josh Coalson committed
319
320
		}
	}
321
322
	decoder->private_->output_capacity = 0;
	decoder->private_->output_channels = 0;
323

Josh Coalson's avatar
Josh Coalson committed
324
	set_defaults_(decoder);
325

326
	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
327
328
}

329
FLAC_API FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value)
330
{
Josh Coalson's avatar
Josh Coalson committed
331
332
333
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
334
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
335
		return false;
336
	decoder->private_->read_callback = value;
337
338
339
	return true;
}

340
FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value)
341
{
Josh Coalson's avatar
Josh Coalson committed
342
343
344
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
345
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
346
		return false;
347
	decoder->private_->write_callback = value;
348
349
350
	return true;
}

351
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value)
352
{
Josh Coalson's avatar
Josh Coalson committed
353
354
355
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
356
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
357
		return false;
358
	decoder->private_->metadata_callback = value;
359
360
361
	return true;
}

362
FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value)
363
{
Josh Coalson's avatar
Josh Coalson committed
364
365
366
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
367
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
368
		return false;
369
	decoder->private_->error_callback = value;
370
371
372
	return true;
}

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

384
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
385
{
Josh Coalson's avatar
Josh Coalson committed
386
387
388
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
389
390
391
392
393
394
395
396
397
	FLAC__ASSERT(type <= FLAC__METADATA_TYPE_VORBIS_COMMENT);
	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;
}

398
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
399
{
Josh Coalson's avatar
Josh Coalson committed
400
401
402
403
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != id);
404
405
406
407
408
409
410
411
412
	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
413
		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2)))
414
415
416
417
418
419
420
421
422
423
			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;
}

424
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
425
{
426
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
427
428
429
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
430
431
	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
		return false;
432
433
	for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
		decoder->private_->metadata_filter[i] = true;
434
435
436
437
	decoder->private_->metadata_filter_ids_count = 0;
	return true;
}

438
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
439
{
Josh Coalson's avatar
Josh Coalson committed
440
441
442
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
443
444
445
446
447
448
449
450
451
	FLAC__ASSERT(type <= FLAC__METADATA_TYPE_VORBIS_COMMENT);
	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;
}

452
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
453
{
Josh Coalson's avatar
Josh Coalson committed
454
455
456
457
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
	FLAC__ASSERT(0 != id);
458
459
460
461
462
463
464
465
466
	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
467
		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2)))
468
469
470
471
472
473
474
475
476
477
			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;
}

478
FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
479
{
Josh Coalson's avatar
Josh Coalson committed
480
481
482
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
483
484
485
486
487
488
489
	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;
}

490
FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
491
{
Josh Coalson's avatar
Josh Coalson committed
492
493
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
494
	return decoder->protected_->state;
495
496
}

497
FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
498
{
Josh Coalson's avatar
Josh Coalson committed
499
500
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
501
	return decoder->protected_->channels;
502
503
}

504
FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
505
{
Josh Coalson's avatar
Josh Coalson committed
506
507
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
508
	return decoder->protected_->channel_assignment;
509
510
}

511
FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
512
{
Josh Coalson's avatar
Josh Coalson committed
513
514
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
515
	return decoder->protected_->bits_per_sample;
516
517
}

518
FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
519
{
Josh Coalson's avatar
Josh Coalson committed
520
521
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
522
	return decoder->protected_->sample_rate;
523
524
}

525
FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
526
{
Josh Coalson's avatar
Josh Coalson committed
527
528
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
529
	return decoder->protected_->blocksize;
Josh Coalson's avatar
Josh Coalson committed
530
531
}

532
FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
533
{
Josh Coalson's avatar
Josh Coalson committed
534
535
536
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
537

538
	if(!FLAC__bitbuffer_clear(decoder->private_->input)) {
539
		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
540
541
		return false;
	}
542
	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
Josh Coalson's avatar
Josh Coalson committed
543
544
545
546

	return true;
}

547
FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
548
{
Josh Coalson's avatar
Josh Coalson committed
549
550
551
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
552
553

	if(!FLAC__stream_decoder_flush(decoder)) {
554
		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
555
556
		return false;
	}
557
	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
Josh Coalson's avatar
Josh Coalson committed
558

559
	decoder->private_->samples_decoded = 0;
Josh Coalson's avatar
Josh Coalson committed
560

Josh Coalson's avatar
Josh Coalson committed
561
562
563
	return true;
}

564
FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
565
{
Josh Coalson's avatar
Josh Coalson committed
566
	FLAC__bool got_a_frame;
Josh Coalson's avatar
Josh Coalson committed
567
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
568
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
569
570

	while(1) {
571
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
572
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
Josh Coalson's avatar
Josh Coalson committed
573
				if(!find_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
574
575
576
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_METADATA:
Josh Coalson's avatar
Josh Coalson committed
577
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
578
					return false; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
579
580
				else
					return true;
Josh Coalson's avatar
Josh Coalson committed
581
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
Josh Coalson's avatar
Josh Coalson committed
582
				if(!frame_sync_(decoder))
Josh Coalson's avatar
Josh Coalson committed
583
584
585
					return true; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_FRAME:
Josh Coalson's avatar
Josh Coalson committed
586
				if(!read_frame_(decoder, &got_a_frame))
Josh Coalson's avatar
Josh Coalson committed
587
					return false; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
588
589
				if(got_a_frame)
					return true; /* above function sets the status for us */
Josh Coalson's avatar
Josh Coalson committed
590
591
				break;
			case FLAC__STREAM_DECODER_END_OF_STREAM:
592
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
593
594
				return true;
			default:
595
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
596
				return false;
Josh Coalson's avatar
Josh Coalson committed
597
598
599
600
		}
	}
}

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

	while(1) {
607
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
608
			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
Josh Coalson's avatar
Josh Coalson committed
609
				if(!find_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
610
611
612
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_METADATA:
Josh Coalson's avatar
Josh Coalson committed
613
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
614
615
616
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
617
			case FLAC__STREAM_DECODER_READ_FRAME:
Josh Coalson's avatar
Josh Coalson committed
618
			case FLAC__STREAM_DECODER_END_OF_STREAM:
619
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
620
621
				return true;
			default:
622
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
623
				return false;
Josh Coalson's avatar
Josh Coalson committed
624
625
626
627
		}
	}
}

628
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
629
{
Josh Coalson's avatar
Josh Coalson committed
630
	FLAC__bool dummy;
Josh Coalson's avatar
Josh Coalson committed
631
	FLAC__ASSERT(0 != decoder);
Josh Coalson's avatar
Josh Coalson committed
632
	FLAC__ASSERT(0 != decoder->protected_);
Josh Coalson's avatar
Josh Coalson committed
633
634

	while(1) {
635
		switch(decoder->protected_->state) {
Josh Coalson's avatar
Josh Coalson committed
636
637
638
			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
639
				break;
Josh Coalson's avatar
Josh Coalson committed
640
641
			case FLAC__STREAM_DECODER_READ_METADATA:
				if(!read_metadata_(decoder))
Josh Coalson's avatar
Josh Coalson committed
642
643
644
					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
645
				if(!frame_sync_(decoder))
Josh Coalson's avatar
Josh Coalson committed
646
647
648
					return true; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_READ_FRAME:
Josh Coalson's avatar
Josh Coalson committed
649
				if(!read_frame_(decoder, &dummy))
Josh Coalson's avatar
Josh Coalson committed
650
651
652
					return false; /* above function sets the status for us */
				break;
			case FLAC__STREAM_DECODER_END_OF_STREAM:
653
			case FLAC__STREAM_DECODER_ABORTED:
Josh Coalson's avatar
Josh Coalson committed
654
655
				return true;
			default:
656
				FLAC__ASSERT(0);
Josh Coalson's avatar
Josh Coalson committed
657
				return false;
Josh Coalson's avatar
Josh Coalson committed
658
659
660
661
		}
	}
}

662
663
664
665
666
667
/***********************************************************************
 *
 * Protected class methods
 *
 ***********************************************************************/

668
unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
669
{
Josh Coalson's avatar
Josh Coalson committed
670
	FLAC__ASSERT(0 != decoder);
671
	return FLAC__bitbuffer_get_input_bytes_unconsumed(decoder->private_->input);
Josh Coalson's avatar
Josh Coalson committed
672
673
}

674
675
676
677
678
679
/***********************************************************************
 *
 * Private class methods
 *
 ***********************************************************************/

Josh Coalson's avatar
Josh Coalson committed
680
void set_defaults_(FLAC__StreamDecoder *decoder)
681
682
683
684
685
686
687
688
689
690
691
692
{
	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
693
FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
Josh Coalson's avatar
Josh Coalson committed
694
695
{
	unsigned i;
Josh Coalson's avatar
Josh Coalson committed
696
	FLAC__int32 *tmp;
Josh Coalson's avatar
Josh Coalson committed
697

698
	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
Josh Coalson's avatar
Josh Coalson committed
699
700
		return true;

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

Josh Coalson's avatar
Josh Coalson committed
703
	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
Josh Coalson's avatar
Josh Coalson committed
704
		if(0 != decoder->private_->output[i]) {
705
			free(decoder->private_->output[i]-4);
706
			decoder->private_->output[i] = 0;
Josh Coalson's avatar
Josh Coalson committed
707
		}
Josh Coalson's avatar
Josh Coalson committed
708
		if(0 != decoder->private_->residual[i]) {
709
710
			free(decoder->private_->residual[i]);
			decoder->private_->residual[i] = 0;
711
		}
Josh Coalson's avatar
Josh Coalson committed
712
713
	}

714
	for(i = 0; i < channels; i++) {
715
716
717
718
719
720
		/* 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.
		 */
721
		tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4));
Josh Coalson's avatar
Josh Coalson committed
722
		if(tmp == 0) {
723
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson's avatar
Josh Coalson committed
724
725
			return false;
		}
726
		memset(tmp, 0, sizeof(FLAC__int32)*4);
727
		decoder->private_->output[i] = tmp + 4;
728

Josh Coalson's avatar
Josh Coalson committed
729
		tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*size);
730
		if(tmp == 0) {
731
			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
732
733
			return false;
		}
734
		decoder->private_->residual[i] = tmp;
Josh Coalson's avatar
Josh Coalson committed
735
736
	}

737
738
	decoder->private_->output_capacity = size;
	decoder->private_->output_channels = channels;
Josh Coalson's avatar
Josh Coalson committed
739
740
741
742

	return true;
}

Josh Coalson's avatar
Josh Coalson committed
743
FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
744
745
746
747
748
749
750
751
752
753
754
755
756
{
	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
757
FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
758
{
Josh Coalson's avatar
Josh Coalson committed
759
	FLAC__uint32 x;
Josh Coalson's avatar
Josh Coalson committed
760
	unsigned i, id;
Josh Coalson's avatar
Josh Coalson committed
761
	FLAC__bool first = true;
Josh Coalson's avatar
Josh Coalson committed
762

763
	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
Josh Coalson's avatar
Josh Coalson committed
764
765

	for(i = id = 0; i < 4; ) {
766
767
768
		if(decoder->private_->cached) {
			x = (FLAC__uint32)decoder->private_->lookahead;
			decoder->private_->cached = false;
769
770
		}
		else {
771
			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
772
773
				return false; /* the read_callback_ sets the state for us */
		}
Josh Coalson's avatar
Josh Coalson committed
774
		if(x == FLAC__STREAM_SYNC_STRING[i]) {
775
			first = true;
Josh Coalson's avatar
Josh Coalson committed
776
777
778
779
780
781
782
783
			i++;
			id = 0;
			continue;
		}
		if(x == ID3V2_TAG_[id]) {
			id++;
			i = 0;
			if(id == 3) {
Josh Coalson's avatar
Josh Coalson committed
784
				if(!skip_id3v2_tag_(decoder))
Josh Coalson's avatar
Josh Coalson committed
785
786
787
788
789
					return false; /* the read_callback_ sets the state for us */
			}
			continue;
		}
		if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
790
			decoder->private_->header_warmup[0] = (FLAC__byte)x;
791
			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
Josh Coalson's avatar
Josh Coalson committed
792
				return false; /* the read_callback_ sets the state for us */
793
794
795
796

			/* 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 */
797
798
				decoder->private_->lookahead = (FLAC__byte)x;
				decoder->private_->cached = true;
799
800
			}
			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
801
802
				decoder->private_->header_warmup[1] = (FLAC__byte)x;
				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
Josh Coalson's avatar
Josh Coalson committed
803
804
805
806
807
				return true;
			}
		}
		i = 0;
		if(first) {
808
			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
809
			first = false;
Josh Coalson's avatar
Josh Coalson committed
810
811
812
		}
	}

813
	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
Josh Coalson's avatar
Josh Coalson committed
814
815
816
	return true;
}

Josh Coalson's avatar
Josh Coalson committed
817
FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
Josh Coalson's avatar
Josh Coalson committed
818
{
819
820
	FLAC__bool is_last;
	FLAC__uint32 i, x, type, length;
Josh Coalson's avatar
Josh Coalson committed
821

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

824
	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
825
		return false; /* the read_callback_ sets the state for us */
826
827
	is_last = x? true : false;

828
	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
829
		return false; /* the read_callback_ sets the state for us */
830

831
	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
832
		return false; /* the read_callback_ sets the state for us */
Josh Coalson's avatar
Josh Coalson committed
833

834
835
836
	if(type == FLAC__METADATA_TYPE_STREAMINFO) {
		if(!read_metadata_streaminfo_(decoder, is_last, length))
			return false;
837

838
		decoder->private_->has_stream_info = true;
839
840
		if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO])
			decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
841
842
	}
	else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
843
		if(!read_metadata_seektable_(decoder, is_last, length))
844
			return false;
845

846
		decoder->private_->has_seek_table = true;
847
848
		if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE])
			decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
Josh Coalson's avatar
Josh Coalson committed
849
850
	}
	else {
851
852
		FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
		unsigned real_length = length;
853
		FLAC__StreamMetadata block;
854

855
		block.is_last = is_last;
Josh Coalson's avatar
Josh Coalson committed
856
		block.type = (FLAC__MetadataType)type;
857
858
		block.length = length;

859
		if(type == FLAC__METADATA_TYPE_APPLICATION) {
860
861
862
863
864
			if(!FLAC__bitbuffer_read_byte_block_aligned(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8, read_callback_, decoder))
				return false; /* the read_callback_ sets the state for us */

			real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;

Josh Coalson's avatar
Josh Coalson committed
865
			if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id))
866
867
868
869
870
				skip_it = !skip_it;
		}

		if(skip_it) {
			if(!FLAC__bitbuffer_read_byte_block_aligned(decoder->private_->input, 0, real_length, read_callback_, decoder))
Josh Coalson's avatar
Josh Coalson committed
871
872
				return false; /* the read_callback_ sets the state for us */
		}
873
874
875
876
877
878
879
880
881
		else {
			switch(type) {
				case FLAC__METADATA_TYPE_PADDING:
					/* skip the padding bytes */
					if(!FLAC__bitbuffer_read_byte_block_aligned(decoder->private_->input, 0, real_length, read_callback_, decoder))
						return false; /* the read_callback_ sets the state for us */
					break;
				case FLAC__METADATA_TYPE_APPLICATION:
					/* remember, we read the ID already */
882
					if(real_length > 0) {
Josh Coalson's avatar
Josh Coalson committed
883
						if(0 == (block.data.application.data = (FLAC__byte*)malloc(real_length))) {
884
885
886
887
888
							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
							return false;
						}
						if(!FLAC__bitbuffer_read_byte_block_aligned(decoder->private_->input, block.data.application.data, real_length, read_callback_, decoder))
							return false; /* the read_callback_ sets the state for us */
889
					}
890
891
					else
						block.data.application.data = 0;
892
893
					break;
				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
894
895
					if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment))
						return false;
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
					break;
				case FLAC__METADATA_TYPE_STREAMINFO:
				case FLAC__METADATA_TYPE_SEEKTABLE:
				default:
					FLAC__ASSERT(0);
			}
			decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);

			/* now we have to free any malloc'ed data in the block */
			switch(type) {
				case FLAC__METADATA_TYPE_PADDING:
					break;
				case FLAC__METADATA_TYPE_APPLICATION:
					if(0 != block.data.application.data)
						free(block.data.application.data);
					break;
				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
					if(0 != block.data.vorbis_comment.vendor_string.entry)
						free(block.data.vorbis_comment.vendor_string.entry);
					if(block.data.vorbis_comment.num_comments > 0)
						for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
							if(0 != block.data.vorbis_comment.comments[i].entry)
								free(block.data.vorbis_comment.comments[i].entry);
					if(0 != block.data.vorbis_comment.comments)
						free(block.data.vorbis_comment.comments);
					break;
				case FLAC__METADATA_TYPE_STREAMINFO:
				case FLAC__METADATA_TYPE_SEEKTABLE:
				default:
					FLAC__ASSERT(0);
			}
		}
Josh Coalson's avatar
Josh Coalson committed
928
929
	}

Josh Coalson's avatar