1/* libFLAC++ - Free Lossless Audio Codec library
2 * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#define __STDC_LIMIT_MACROS 1 /* otherwise SIZE_MAX is not defined for c++ */
33#include "share/alloc.h"
34#include "FLAC++/metadata.h"
35#include "FLAC/assert.h"
36#include <stdlib.h> // for malloc(), free()
37#include <string.h> // for memcpy() etc.
38
39#ifdef _MSC_VER
40// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
41#pragma warning ( disable : 4800 )
42#endif
43
44namespace FLAC {
45	namespace Metadata {
46
47		// local utility routines
48
49		namespace local {
50
51			Prototype *construct_block(::FLAC__StreamMetadata *object)
52			{
53				Prototype *ret = 0;
54				switch(object->type) {
55					case FLAC__METADATA_TYPE_STREAMINFO:
56						ret = new StreamInfo(object, /*copy=*/false);
57						break;
58					case FLAC__METADATA_TYPE_PADDING:
59						ret = new Padding(object, /*copy=*/false);
60						break;
61					case FLAC__METADATA_TYPE_APPLICATION:
62						ret = new Application(object, /*copy=*/false);
63						break;
64					case FLAC__METADATA_TYPE_SEEKTABLE:
65						ret = new SeekTable(object, /*copy=*/false);
66						break;
67					case FLAC__METADATA_TYPE_VORBIS_COMMENT:
68						ret = new VorbisComment(object, /*copy=*/false);
69						break;
70					case FLAC__METADATA_TYPE_CUESHEET:
71						ret = new CueSheet(object, /*copy=*/false);
72						break;
73					case FLAC__METADATA_TYPE_PICTURE:
74						ret = new Picture(object, /*copy=*/false);
75						break;
76					default:
77						ret = new Unknown(object, /*copy=*/false);
78						break;
79				}
80				return ret;
81			}
82
83		}
84
85		FLACPP_API Prototype *clone(const Prototype *object)
86		{
87			FLAC__ASSERT(0 != object);
88
89			const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
90			const Padding *padding = dynamic_cast<const Padding *>(object);
91			const Application *application = dynamic_cast<const Application *>(object);
92			const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
93			const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
94			const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
95			const Picture *picture = dynamic_cast<const Picture *>(object);
96			const Unknown *unknown = dynamic_cast<const Unknown *>(object);
97
98			if(0 != streaminfo)
99				return new StreamInfo(*streaminfo);
100			else if(0 != padding)
101				return new Padding(*padding);
102			else if(0 != application)
103				return new Application(*application);
104			else if(0 != seektable)
105				return new SeekTable(*seektable);
106			else if(0 != vorbiscomment)
107				return new VorbisComment(*vorbiscomment);
108			else if(0 != cuesheet)
109				return new CueSheet(*cuesheet);
110			else if(0 != picture)
111				return new Picture(*picture);
112			else if(0 != unknown)
113				return new Unknown(*unknown);
114			else {
115				FLAC__ASSERT(0);
116				return 0;
117			}
118		}
119
120		//
121		// Prototype
122		//
123
124		Prototype::Prototype(const Prototype &object):
125		object_(::FLAC__metadata_object_clone(object.object_)),
126		is_reference_(false)
127		{
128			FLAC__ASSERT(object.is_valid());
129		}
130
131		Prototype::Prototype(const ::FLAC__StreamMetadata &object):
132		object_(::FLAC__metadata_object_clone(&object)),
133		is_reference_(false)
134		{
135		}
136
137		Prototype::Prototype(const ::FLAC__StreamMetadata *object):
138		object_(::FLAC__metadata_object_clone(object)),
139		is_reference_(false)
140		{
141			FLAC__ASSERT(0 != object);
142		}
143
144		Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy):
145		object_(copy? ::FLAC__metadata_object_clone(object) : object),
146		is_reference_(false)
147		{
148			FLAC__ASSERT(0 != object);
149		}
150
151		Prototype::~Prototype()
152		{
153			clear();
154		}
155
156		void Prototype::clear()
157		{
158			if(0 != object_ && !is_reference_)
159				FLAC__metadata_object_delete(object_);
160			object_ = 0;
161		}
162
163		Prototype &Prototype::operator=(const Prototype &object)
164		{
165			FLAC__ASSERT(object.is_valid());
166			clear();
167			is_reference_ = false;
168			object_ = ::FLAC__metadata_object_clone(object.object_);
169			return *this;
170		}
171
172		Prototype &Prototype::operator=(const ::FLAC__StreamMetadata &object)
173		{
174			clear();
175			is_reference_ = false;
176			object_ = ::FLAC__metadata_object_clone(&object);
177			return *this;
178		}
179
180		Prototype &Prototype::operator=(const ::FLAC__StreamMetadata *object)
181		{
182			FLAC__ASSERT(0 != object);
183			clear();
184			is_reference_ = false;
185			object_ = ::FLAC__metadata_object_clone(object);
186			return *this;
187		}
188
189		Prototype &Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy)
190		{
191			FLAC__ASSERT(0 != object);
192			clear();
193			object_ = (copy? ::FLAC__metadata_object_clone(object) : object);
194			is_reference_ = false;
195			return *this;
196		}
197
198		bool Prototype::get_is_last() const
199		{
200			FLAC__ASSERT(is_valid());
201			return (bool)object_->is_last;
202		}
203
204		FLAC__MetadataType Prototype::get_type() const
205		{
206			FLAC__ASSERT(is_valid());
207			return object_->type;
208		}
209
210		unsigned Prototype::get_length() const
211		{
212			FLAC__ASSERT(is_valid());
213			return object_->length;
214		}
215
216		void Prototype::set_is_last(bool value)
217		{
218			FLAC__ASSERT(is_valid());
219			object_->is_last = value;
220		}
221
222
223		//
224		// StreamInfo
225		//
226
227		StreamInfo::StreamInfo():
228		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
229		{ }
230
231		StreamInfo::~StreamInfo()
232		{ }
233
234		unsigned StreamInfo::get_min_blocksize() const
235		{
236			FLAC__ASSERT(is_valid());
237			return object_->data.stream_info.min_blocksize;
238		}
239
240		unsigned StreamInfo::get_max_blocksize() const
241		{
242			FLAC__ASSERT(is_valid());
243			return object_->data.stream_info.max_blocksize;
244		}
245
246		unsigned StreamInfo::get_min_framesize() const
247		{
248			FLAC__ASSERT(is_valid());
249			return object_->data.stream_info.min_framesize;
250		}
251
252		unsigned StreamInfo::get_max_framesize() const
253		{
254			FLAC__ASSERT(is_valid());
255			return object_->data.stream_info.max_framesize;
256		}
257
258		unsigned StreamInfo::get_sample_rate() const
259		{
260			FLAC__ASSERT(is_valid());
261			return object_->data.stream_info.sample_rate;
262		}
263
264		unsigned StreamInfo::get_channels() const
265		{
266			FLAC__ASSERT(is_valid());
267			return object_->data.stream_info.channels;
268		}
269
270		unsigned StreamInfo::get_bits_per_sample() const
271		{
272			FLAC__ASSERT(is_valid());
273			return object_->data.stream_info.bits_per_sample;
274		}
275
276		FLAC__uint64 StreamInfo::get_total_samples() const
277		{
278			FLAC__ASSERT(is_valid());
279			return object_->data.stream_info.total_samples;
280		}
281
282		const FLAC__byte *StreamInfo::get_md5sum() const
283		{
284			FLAC__ASSERT(is_valid());
285			return object_->data.stream_info.md5sum;
286		}
287
288		void StreamInfo::set_min_blocksize(unsigned value)
289		{
290			FLAC__ASSERT(is_valid());
291			FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
292			FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
293			object_->data.stream_info.min_blocksize = value;
294		}
295
296		void StreamInfo::set_max_blocksize(unsigned value)
297		{
298			FLAC__ASSERT(is_valid());
299			FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
300			FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
301			object_->data.stream_info.max_blocksize = value;
302		}
303
304		void StreamInfo::set_min_framesize(unsigned value)
305		{
306			FLAC__ASSERT(is_valid());
307			FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
308			object_->data.stream_info.min_framesize = value;
309		}
310
311		void StreamInfo::set_max_framesize(unsigned value)
312		{
313			FLAC__ASSERT(is_valid());
314			FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
315			object_->data.stream_info.max_framesize = value;
316		}
317
318		void StreamInfo::set_sample_rate(unsigned value)
319		{
320			FLAC__ASSERT(is_valid());
321			FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
322			object_->data.stream_info.sample_rate = value;
323		}
324
325		void StreamInfo::set_channels(unsigned value)
326		{
327			FLAC__ASSERT(is_valid());
328			FLAC__ASSERT(value > 0);
329			FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
330			object_->data.stream_info.channels = value;
331		}
332
333		void StreamInfo::set_bits_per_sample(unsigned value)
334		{
335			FLAC__ASSERT(is_valid());
336			FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
337			FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
338			object_->data.stream_info.bits_per_sample = value;
339		}
340
341		void StreamInfo::set_total_samples(FLAC__uint64 value)
342		{
343			FLAC__ASSERT(is_valid());
344			FLAC__ASSERT(value < (((FLAC__uint64)1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
345			object_->data.stream_info.total_samples = value;
346		}
347
348		void StreamInfo::set_md5sum(const FLAC__byte value[16])
349		{
350			FLAC__ASSERT(is_valid());
351			FLAC__ASSERT(0 != value);
352			memcpy(object_->data.stream_info.md5sum, value, 16);
353		}
354
355
356		//
357		// Padding
358		//
359
360		Padding::Padding():
361		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
362		{ }
363
364		Padding::~Padding()
365		{ }
366
367		void Padding::set_length(unsigned length)
368		{
369			FLAC__ASSERT(is_valid());
370			object_->length = length;
371		}
372
373
374		//
375		// Application
376		//
377
378		Application::Application():
379		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
380		{ }
381
382		Application::~Application()
383		{ }
384
385		const FLAC__byte *Application::get_id() const
386		{
387			FLAC__ASSERT(is_valid());
388			return object_->data.application.id;
389		}
390
391		const FLAC__byte *Application::get_data() const
392		{
393			FLAC__ASSERT(is_valid());
394			return object_->data.application.data;
395		}
396
397		void Application::set_id(const FLAC__byte value[4])
398		{
399			FLAC__ASSERT(is_valid());
400			FLAC__ASSERT(0 != value);
401			memcpy(object_->data.application.id, value, 4);
402		}
403
404		bool Application::set_data(const FLAC__byte *data, unsigned length)
405		{
406			FLAC__ASSERT(is_valid());
407			return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
408		}
409
410		bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
411		{
412			FLAC__ASSERT(is_valid());
413			return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
414		}
415
416
417		//
418		// SeekTable
419		//
420
421		SeekTable::SeekTable():
422		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
423		{ }
424
425		SeekTable::~SeekTable()
426		{ }
427
428		unsigned SeekTable::get_num_points() const
429		{
430			FLAC__ASSERT(is_valid());
431			return object_->data.seek_table.num_points;
432		}
433
434		::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
435		{
436			FLAC__ASSERT(is_valid());
437			FLAC__ASSERT(index < object_->data.seek_table.num_points);
438			return object_->data.seek_table.points[index];
439		}
440
441		void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
442		{
443			FLAC__ASSERT(is_valid());
444			FLAC__ASSERT(index < object_->data.seek_table.num_points);
445			::FLAC__metadata_object_seektable_set_point(object_, index, point);
446		}
447
448		bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
449		{
450			FLAC__ASSERT(is_valid());
451			FLAC__ASSERT(index <= object_->data.seek_table.num_points);
452			return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
453		}
454
455		bool SeekTable::delete_point(unsigned index)
456		{
457			FLAC__ASSERT(is_valid());
458			FLAC__ASSERT(index < object_->data.seek_table.num_points);
459			return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
460		}
461
462		bool SeekTable::is_legal() const
463		{
464			FLAC__ASSERT(is_valid());
465			return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
466		}
467
468
469		//
470		// VorbisComment::Entry
471		//
472
473		VorbisComment::Entry::Entry()
474		{
475			zero();
476		}
477
478		VorbisComment::Entry::Entry(const char *field, unsigned field_length)
479		{
480			zero();
481			construct(field, field_length);
482		}
483
484		VorbisComment::Entry::Entry(const char *field)
485		{
486			zero();
487			construct(field);
488		}
489
490		VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
491		{
492			zero();
493			construct(field_name, field_value, field_value_length);
494		}
495
496		VorbisComment::Entry::Entry(const char *field_name, const char *field_value)
497		{
498			zero();
499			construct(field_name, field_value);
500		}
501
502		VorbisComment::Entry::Entry(const Entry &entry)
503		{
504			FLAC__ASSERT(entry.is_valid());
505			zero();
506			construct((const char *)entry.entry_.entry, entry.entry_.length);
507		}
508
509		VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
510		{
511			FLAC__ASSERT(entry.is_valid());
512			clear();
513			construct((const char *)entry.entry_.entry, entry.entry_.length);
514			return *this;
515		}
516
517		VorbisComment::Entry::~Entry()
518		{
519			clear();
520		}
521
522		bool VorbisComment::Entry::is_valid() const
523		{
524			return is_valid_;
525		}
526
527		unsigned VorbisComment::Entry::get_field_length() const
528		{
529			FLAC__ASSERT(is_valid());
530			return entry_.length;
531		}
532
533		unsigned VorbisComment::Entry::get_field_name_length() const
534		{
535			FLAC__ASSERT(is_valid());
536			return field_name_length_;
537		}
538
539		unsigned VorbisComment::Entry::get_field_value_length() const
540		{
541			FLAC__ASSERT(is_valid());
542			return field_value_length_;
543		}
544
545		::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
546		{
547			FLAC__ASSERT(is_valid());
548			return entry_;
549		}
550
551		const char *VorbisComment::Entry::get_field() const
552		{
553			FLAC__ASSERT(is_valid());
554			return (const char *)entry_.entry;
555		}
556
557		const char *VorbisComment::Entry::get_field_name() const
558		{
559			FLAC__ASSERT(is_valid());
560			return field_name_;
561		}
562
563		const char *VorbisComment::Entry::get_field_value() const
564		{
565			FLAC__ASSERT(is_valid());
566			return field_value_;
567		}
568
569		bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
570		{
571			FLAC__ASSERT(is_valid());
572			FLAC__ASSERT(0 != field);
573
574			if(!::FLAC__format_vorbiscomment_entry_is_legal((const ::FLAC__byte*)field, field_length))
575				return is_valid_ = false;
576
577			clear_entry();
578
579			if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_2op_(field_length, /*+*/1))) {
580				is_valid_ = false;
581			}
582			else {
583				entry_.length = field_length;
584				memcpy(entry_.entry, field, field_length);
585				entry_.entry[field_length] = '\0';
586				(void) parse_field();
587			}
588
589			return is_valid_;
590		}
591
592		bool VorbisComment::Entry::set_field(const char *field)
593		{
594			return set_field(field, strlen(field));
595		}
596
597		bool VorbisComment::Entry::set_field_name(const char *field_name)
598		{
599			FLAC__ASSERT(is_valid());
600			FLAC__ASSERT(0 != field_name);
601
602			if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
603				return is_valid_ = false;
604
605			clear_field_name();
606
607			if(0 == (field_name_ = strdup(field_name))) {
608				is_valid_ = false;
609			}
610			else {
611				field_name_length_ = strlen(field_name_);
612				compose_field();
613			}
614
615			return is_valid_;
616		}
617
618		bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
619		{
620			FLAC__ASSERT(is_valid());
621			FLAC__ASSERT(0 != field_value);
622
623			if(!::FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte*)field_value, field_value_length))
624				return is_valid_ = false;
625
626			clear_field_value();
627
628			if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length, /*+*/1))) {
629				is_valid_ = false;
630			}
631			else {
632				field_value_length_ = field_value_length;
633				memcpy(field_value_, field_value, field_value_length);
634				field_value_[field_value_length] = '\0';
635				compose_field();
636			}
637
638			return is_valid_;
639		}
640
641		bool VorbisComment::Entry::set_field_value(const char *field_value)
642		{
643			return set_field_value(field_value, strlen(field_value));
644		}
645
646		void VorbisComment::Entry::zero()
647		{
648			is_valid_ = true;
649			entry_.length = 0;
650			entry_.entry = 0;
651			field_name_ = 0;
652			field_name_length_ = 0;
653			field_value_ = 0;
654			field_value_length_ = 0;
655		}
656
657		void VorbisComment::Entry::clear()
658		{
659			clear_entry();
660			clear_field_name();
661			clear_field_value();
662			is_valid_ = true;
663		}
664
665		void VorbisComment::Entry::clear_entry()
666		{
667			if(0 != entry_.entry) {
668				free(entry_.entry);
669				entry_.entry = 0;
670				entry_.length = 0;
671			}
672		}
673
674		void VorbisComment::Entry::clear_field_name()
675		{
676			if(0 != field_name_) {
677				free(field_name_);
678				field_name_ = 0;
679				field_name_length_ = 0;
680			}
681		}
682
683		void VorbisComment::Entry::clear_field_value()
684		{
685			if(0 != field_value_) {
686				free(field_value_);
687				field_value_ = 0;
688				field_value_length_ = 0;
689			}
690		}
691
692		void VorbisComment::Entry::construct(const char *field, unsigned field_length)
693		{
694			if(set_field(field, field_length))
695				parse_field();
696		}
697
698		void VorbisComment::Entry::construct(const char *field)
699		{
700			construct(field, strlen(field));
701		}
702
703		void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
704		{
705			if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
706				compose_field();
707		}
708
709		void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
710		{
711			construct(field_name, field_value, strlen(field_value));
712		}
713
714		void VorbisComment::Entry::compose_field()
715		{
716			clear_entry();
717
718			if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1))) {
719				is_valid_ = false;
720			}
721			else {
722				memcpy(entry_.entry, field_name_, field_name_length_);
723				entry_.length += field_name_length_;
724				memcpy(entry_.entry + entry_.length, "=", 1);
725				entry_.length += 1;
726				memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
727				entry_.length += field_value_length_;
728				entry_.entry[entry_.length] = '\0';
729				is_valid_ = true;
730			}
731		}
732
733		void VorbisComment::Entry::parse_field()
734		{
735			clear_field_name();
736			clear_field_value();
737
738			const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
739
740			if(0 == p)
741				p = (const char *)entry_.entry + entry_.length;
742
743			field_name_length_ = (unsigned)(p - (const char *)entry_.entry);
744			if(0 == (field_name_ = (char *)safe_malloc_add_2op_(field_name_length_, /*+*/1))) { // +1 for the trailing \0
745				is_valid_ = false;
746				return;
747			}
748			memcpy(field_name_, entry_.entry, field_name_length_);
749			field_name_[field_name_length_] = '\0';
750
751			if(entry_.length - field_name_length_ == 0) {
752				field_value_length_ = 0;
753				if(0 == (field_value_ = (char *)safe_malloc_(0))) {
754					is_valid_ = false;
755					return;
756				}
757			}
758			else {
759				field_value_length_ = entry_.length - field_name_length_ - 1;
760				if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length_, /*+*/1))) { // +1 for the trailing \0
761					is_valid_ = false;
762					return;
763				}
764				memcpy(field_value_, ++p, field_value_length_);
765				field_value_[field_value_length_] = '\0';
766			}
767
768			is_valid_ = true;
769		}
770
771
772		//
773		// VorbisComment
774		//
775
776		VorbisComment::VorbisComment():
777		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
778		{ }
779
780		VorbisComment::~VorbisComment()
781		{ }
782
783		unsigned VorbisComment::get_num_comments() const
784		{
785			FLAC__ASSERT(is_valid());
786			return object_->data.vorbis_comment.num_comments;
787		}
788
789		const FLAC__byte *VorbisComment::get_vendor_string() const
790		{
791			FLAC__ASSERT(is_valid());
792			return object_->data.vorbis_comment.vendor_string.entry;
793		}
794
795		VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
796		{
797			FLAC__ASSERT(is_valid());
798			FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
799			return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
800		}
801
802		bool VorbisComment::set_vendor_string(const FLAC__byte *string)
803		{
804			FLAC__ASSERT(is_valid());
805			// vendor_string is a special kind of entry
806			const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { strlen((const char *)string), (FLAC__byte*)string }; // we can cheat on const-ness because we make a copy below:
807			return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
808		}
809
810		bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
811		{
812			FLAC__ASSERT(is_valid());
813			FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
814			return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
815		}
816
817		bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
818		{
819			FLAC__ASSERT(is_valid());
820			FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
821			return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
822		}
823
824		bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
825		{
826			FLAC__ASSERT(is_valid());
827			return (bool)::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true);
828		}
829
830		bool VorbisComment::delete_comment(unsigned index)
831		{
832			FLAC__ASSERT(is_valid());
833			FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
834			return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
835		}
836
837
838		//
839		// CueSheet::Track
840		//
841
842		CueSheet::Track::Track():
843		object_(::FLAC__metadata_object_cuesheet_track_new())
844		{ }
845
846		CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track):
847		object_(::FLAC__metadata_object_cuesheet_track_clone(track))
848		{ }
849
850		CueSheet::Track::Track(const Track &track):
851		object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_))
852		{ }
853
854		CueSheet::Track &CueSheet::Track::operator=(const Track &track)
855		{
856			if(0 != object_)
857				::FLAC__metadata_object_cuesheet_track_delete(object_);
858			object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_);
859			return *this;
860		}
861
862		CueSheet::Track::~Track()
863		{
864			if(0 != object_)
865				::FLAC__metadata_object_cuesheet_track_delete(object_);
866		}
867
868		bool CueSheet::Track::is_valid() const
869		{
870			return(0 != object_);
871		}
872
873		::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(unsigned i) const
874		{
875			FLAC__ASSERT(is_valid());
876			FLAC__ASSERT(i < object_->num_indices);
877			return object_->indices[i];
878		}
879
880		void CueSheet::Track::set_isrc(const char value[12])
881		{
882			FLAC__ASSERT(is_valid());
883			FLAC__ASSERT(0 != value);
884			memcpy(object_->isrc, value, 12);
885			object_->isrc[12] = '\0';
886		}
887
888		void CueSheet::Track::set_type(unsigned value)
889		{
890			FLAC__ASSERT(is_valid());
891			FLAC__ASSERT(value <= 1);
892			object_->type = value;
893		}
894
895 		void CueSheet::Track::set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index)
896 		{
897 			FLAC__ASSERT(is_valid());
898 			FLAC__ASSERT(i < object_->num_indices);
899 			object_->indices[i] = index;
900 		}
901
902
903		//
904		// CueSheet
905		//
906
907		CueSheet::CueSheet():
908		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false)
909		{ }
910
911		CueSheet::~CueSheet()
912		{ }
913
914		const char *CueSheet::get_media_catalog_number() const
915		{
916			FLAC__ASSERT(is_valid());
917			return object_->data.cue_sheet.media_catalog_number;
918		}
919
920		FLAC__uint64 CueSheet::get_lead_in() const
921		{
922			FLAC__ASSERT(is_valid());
923			return object_->data.cue_sheet.lead_in;
924		}
925
926		bool CueSheet::get_is_cd() const
927		{
928			FLAC__ASSERT(is_valid());
929			return object_->data.cue_sheet.is_cd? true : false;
930		}
931
932		unsigned CueSheet::get_num_tracks() const
933		{
934			FLAC__ASSERT(is_valid());
935			return object_->data.cue_sheet.num_tracks;
936		}
937
938		CueSheet::Track CueSheet::get_track(unsigned i) const
939		{
940			FLAC__ASSERT(is_valid());
941			FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
942			return Track(object_->data.cue_sheet.tracks + i);
943		}
944
945		void CueSheet::set_media_catalog_number(const char value[128])
946		{
947			FLAC__ASSERT(is_valid());
948			FLAC__ASSERT(0 != value);
949			memcpy(object_->data.cue_sheet.media_catalog_number, value, 128);
950			object_->data.cue_sheet.media_catalog_number[128] = '\0';
951		}
952
953		void CueSheet::set_lead_in(FLAC__uint64 value)
954		{
955			FLAC__ASSERT(is_valid());
956			object_->data.cue_sheet.lead_in = value;
957		}
958
959		void CueSheet::set_is_cd(bool value)
960		{
961			FLAC__ASSERT(is_valid());
962			object_->data.cue_sheet.is_cd = value;
963		}
964
965		void CueSheet::set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
966		{
967			FLAC__ASSERT(is_valid());
968			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
969			FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
970			object_->data.cue_sheet.tracks[track_num].indices[index_num] = index;
971		}
972
973		bool CueSheet::insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
974		{
975			FLAC__ASSERT(is_valid());
976			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
977			FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
978			return (bool)::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, index);
979		}
980
981		bool CueSheet::delete_index(unsigned track_num, unsigned index_num)
982		{
983			FLAC__ASSERT(is_valid());
984			FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
985			FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
986			return (bool)::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num);
987		}
988
989		bool CueSheet::set_track(unsigned i, const CueSheet::Track &track)
990		{
991			FLAC__ASSERT(is_valid());
992			FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
993			// We can safely const_cast since copy=true
994			return (bool)::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
995		}
996
997		bool CueSheet::insert_track(unsigned i, const CueSheet::Track &track)
998		{
999			FLAC__ASSERT(is_valid());
1000			FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
1001			// We can safely const_cast since copy=true
1002			return (bool)::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
1003		}
1004
1005		bool CueSheet::delete_track(unsigned i)
1006		{
1007			FLAC__ASSERT(is_valid());
1008			FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1009			return (bool)::FLAC__metadata_object_cuesheet_delete_track(object_, i);
1010		}
1011
1012		bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
1013		{
1014			FLAC__ASSERT(is_valid());
1015			return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
1016		}
1017
1018		FLAC__uint32 CueSheet::calculate_cddb_id() const
1019		{
1020			FLAC__ASSERT(is_valid());
1021			return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
1022		}
1023
1024
1025		//
1026		// Picture
1027		//
1028
1029		Picture::Picture():
1030		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
1031		{ }
1032
1033		Picture::~Picture()
1034		{ }
1035
1036		::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
1037		{
1038			FLAC__ASSERT(is_valid());
1039			return object_->data.picture.type;
1040		}
1041
1042		const char *Picture::get_mime_type() const
1043		{
1044			FLAC__ASSERT(is_valid());
1045			return object_->data.picture.mime_type;
1046		}
1047
1048		const FLAC__byte *Picture::get_description() const
1049		{
1050			FLAC__ASSERT(is_valid());
1051			return object_->data.picture.description;
1052		}
1053
1054		FLAC__uint32 Picture::get_width() const
1055		{
1056			FLAC__ASSERT(is_valid());
1057			return object_->data.picture.width;
1058		}
1059
1060		FLAC__uint32 Picture::get_height() const
1061		{
1062			FLAC__ASSERT(is_valid());
1063			return object_->data.picture.height;
1064		}
1065
1066		FLAC__uint32 Picture::get_depth() const
1067		{
1068			FLAC__ASSERT(is_valid());
1069			return object_->data.picture.depth;
1070		}
1071
1072		FLAC__uint32 Picture::get_colors() const
1073		{
1074			FLAC__ASSERT(is_valid());
1075			return object_->data.picture.colors;
1076		}
1077
1078		FLAC__uint32 Picture::get_data_length() const
1079		{
1080			FLAC__ASSERT(is_valid());
1081			return object_->data.picture.data_length;
1082		}
1083
1084		const FLAC__byte *Picture::get_data() const
1085		{
1086			FLAC__ASSERT(is_valid());
1087			return object_->data.picture.data;
1088		}
1089
1090		void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
1091		{
1092			FLAC__ASSERT(is_valid());
1093			object_->data.picture.type = type;
1094		}
1095
1096		bool Picture::set_mime_type(const char *string)
1097		{
1098			FLAC__ASSERT(is_valid());
1099			// We can safely const_cast since copy=true
1100			return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true);
1101		}
1102
1103		bool Picture::set_description(const FLAC__byte *string)
1104		{
1105			FLAC__ASSERT(is_valid());
1106			// We can safely const_cast since copy=true
1107			return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true);
1108		}
1109
1110		void Picture::set_width(FLAC__uint32 value) const
1111		{
1112			FLAC__ASSERT(is_valid());
1113			object_->data.picture.width = value;
1114		}
1115
1116		void Picture::set_height(FLAC__uint32 value) const
1117		{
1118			FLAC__ASSERT(is_valid());
1119			object_->data.picture.height = value;
1120		}
1121
1122		void Picture::set_depth(FLAC__uint32 value) const
1123		{
1124			FLAC__ASSERT(is_valid());
1125			object_->data.picture.depth = value;
1126		}
1127
1128		void Picture::set_colors(FLAC__uint32 value) const
1129		{
1130			FLAC__ASSERT(is_valid());
1131			object_->data.picture.colors = value;
1132		}
1133
1134		bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
1135		{
1136			FLAC__ASSERT(is_valid());
1137			// We can safely const_cast since copy=true
1138			return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
1139		}
1140
1141
1142		//
1143		// Unknown
1144		//
1145
1146		Unknown::Unknown():
1147		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
1148		{ }
1149
1150		Unknown::~Unknown()
1151		{ }
1152
1153		const FLAC__byte *Unknown::get_data() const
1154		{
1155			FLAC__ASSERT(is_valid());
1156			return object_->data.application.data;
1157		}
1158
1159		bool Unknown::set_data(const FLAC__byte *data, unsigned length)
1160		{
1161			FLAC__ASSERT(is_valid());
1162			return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
1163		}
1164
1165		bool Unknown::set_data(FLAC__byte *data, unsigned length, bool copy)
1166		{
1167			FLAC__ASSERT(is_valid());
1168			return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
1169		}
1170
1171
1172		// ============================================================
1173		//
1174		//  Level 0
1175		//
1176		// ============================================================
1177
1178		FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
1179		{
1180			FLAC__ASSERT(0 != filename);
1181
1182			::FLAC__StreamMetadata object;
1183
1184			if(::FLAC__metadata_get_streaminfo(filename, &object)) {
1185				streaminfo = object;
1186				return true;
1187			}
1188			else
1189				return false;
1190		}
1191
1192		FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
1193		{
1194			FLAC__ASSERT(0 != filename);
1195
1196			::FLAC__StreamMetadata *object;
1197
1198			tags = 0;
1199
1200			if(::FLAC__metadata_get_tags(filename, &object)) {
1201				tags = new VorbisComment(object, /*copy=*/false);
1202				return true;
1203			}
1204			else
1205				return false;
1206		}
1207
1208		FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
1209		{
1210			FLAC__ASSERT(0 != filename);
1211
1212			::FLAC__StreamMetadata *object;
1213
1214			if(::FLAC__metadata_get_tags(filename, &object)) {
1215				tags.assign(object, /*copy=*/false);
1216				return true;
1217			}
1218			else
1219				return false;
1220		}
1221
1222		FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
1223		{
1224			FLAC__ASSERT(0 != filename);
1225
1226			::FLAC__StreamMetadata *object;
1227
1228			cuesheet = 0;
1229
1230			if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1231				cuesheet = new CueSheet(object, /*copy=*/false);
1232				return true;
1233			}
1234			else
1235				return false;
1236		}
1237
1238		FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
1239		{
1240			FLAC__ASSERT(0 != filename);
1241
1242			::FLAC__StreamMetadata *object;
1243
1244			if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1245				cuesheet.assign(object, /*copy=*/false);
1246				return true;
1247			}
1248			else
1249				return false;
1250		}
1251
1252		FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
1253		{
1254			FLAC__ASSERT(0 != filename);
1255
1256			::FLAC__StreamMetadata *object;
1257
1258			picture = 0;
1259
1260			if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1261				picture = new Picture(object, /*copy=*/false);
1262				return true;
1263			}
1264			else
1265				return false;
1266		}
1267
1268		FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
1269		{
1270			FLAC__ASSERT(0 != filename);
1271
1272			::FLAC__StreamMetadata *object;
1273
1274			if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1275				picture.assign(object, /*copy=*/false);
1276				return true;
1277			}
1278			else
1279				return false;
1280		}
1281
1282
1283		// ============================================================
1284		//
1285		//  Level 1
1286		//
1287		// ============================================================
1288
1289		SimpleIterator::SimpleIterator():
1290		iterator_(::FLAC__metadata_simple_iterator_new())
1291		{ }
1292
1293		SimpleIterator::~SimpleIterator()
1294		{
1295			clear();
1296		}
1297
1298		void SimpleIterator::clear()
1299		{
1300			if(0 != iterator_)
1301				FLAC__metadata_simple_iterator_delete(iterator_);
1302			iterator_ = 0;
1303		}
1304
1305		bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
1306		{
1307			FLAC__ASSERT(0 != filename);
1308			FLAC__ASSERT(is_valid());
1309			return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
1310		}
1311
1312		bool SimpleIterator::is_valid() const
1313		{
1314			return 0 != iterator_;
1315		}
1316
1317		SimpleIterator::Status SimpleIterator::status()
1318		{
1319			FLAC__ASSERT(is_valid());
1320			return Status(::FLAC__metadata_simple_iterator_status(iterator_));
1321		}
1322
1323		bool SimpleIterator::is_writable() const
1324		{
1325			FLAC__ASSERT(is_valid());
1326			return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
1327		}
1328
1329		bool SimpleIterator::next()
1330		{
1331			FLAC__ASSERT(is_valid());
1332			return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
1333		}
1334
1335		bool SimpleIterator::prev()
1336		{
1337			FLAC__ASSERT(is_valid());
1338			return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
1339		}
1340
1341		//@@@@ add to tests
1342		bool SimpleIterator::is_last() const
1343		{
1344			FLAC__ASSERT(is_valid());
1345			return (bool)::FLAC__metadata_simple_iterator_is_last(iterator_);
1346		}
1347
1348		//@@@@ add to tests
1349		off_t SimpleIterator::get_block_offset() const
1350		{
1351			FLAC__ASSERT(is_valid());
1352			return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
1353		}
1354
1355		::FLAC__MetadataType SimpleIterator::get_block_type() const
1356		{
1357			FLAC__ASSERT(is_valid());
1358			return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
1359		}
1360
1361		//@@@@ add to tests
1362		unsigned SimpleIterator::get_block_length() const
1363		{
1364			FLAC__ASSERT(is_valid());
1365			return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
1366		}
1367
1368		//@@@@ add to tests
1369		bool SimpleIterator::get_application_id(FLAC__byte *id)
1370		{
1371			FLAC__ASSERT(is_valid());
1372			return (bool)::FLAC__metadata_simple_iterator_get_application_id(iterator_, id);
1373		}
1374
1375		Prototype *SimpleIterator::get_block()
1376		{
1377			FLAC__ASSERT(is_valid());
1378			return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
1379		}
1380
1381		bool SimpleIterator::set_block(Prototype *block, bool use_padding)
1382		{
1383			FLAC__ASSERT(0 != block);
1384			FLAC__ASSERT(is_valid());
1385			return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
1386		}
1387
1388		bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
1389		{
1390			FLAC__ASSERT(0 != block);
1391			FLAC__ASSERT(is_valid());
1392			return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
1393		}
1394
1395		bool SimpleIterator::delete_block(bool use_padding)
1396		{
1397			FLAC__ASSERT(is_valid());
1398			return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
1399		}
1400
1401
1402		// ============================================================
1403		//
1404		//  Level 2
1405		//
1406		// ============================================================
1407
1408		Chain::Chain():
1409		chain_(::FLAC__metadata_chain_new())
1410		{ }
1411
1412		Chain::~Chain()
1413		{
1414			clear();
1415		}
1416
1417		void Chain::clear()
1418		{
1419			if(0 != chain_)
1420				FLAC__metadata_chain_delete(chain_);
1421			chain_ = 0;
1422		}
1423
1424		bool Chain::is_valid() const
1425		{
1426			return 0 != chain_;
1427		}
1428
1429		Chain::Status Chain::status()
1430		{
1431			FLAC__ASSERT(is_valid());
1432			return Status(::FLAC__metadata_chain_status(chain_));
1433		}
1434
1435		bool Chain::read(const char *filename, bool is_ogg)
1436		{
1437			FLAC__ASSERT(0 != filename);
1438			FLAC__ASSERT(is_valid());
1439			return is_ogg?
1440				(bool)::FLAC__metadata_chain_read_ogg(chain_, filename) :
1441				(bool)::FLAC__metadata_chain_read(chain_, filename)
1442			;
1443		}
1444
1445		bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg)
1446		{
1447			FLAC__ASSERT(is_valid());
1448			return is_ogg?
1449				(bool)::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks) :
1450				(bool)::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks)
1451			;
1452		}
1453
1454		bool Chain::check_if_tempfile_needed(bool use_padding)
1455		{
1456			FLAC__ASSERT(is_valid());
1457			return (bool)::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
1458		}
1459
1460		bool Chain::write(bool use_padding, bool preserve_file_stats)
1461		{
1462			FLAC__ASSERT(is_valid());
1463			return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
1464		}
1465
1466		bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
1467		{
1468			FLAC__ASSERT(is_valid());
1469			return (bool)::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
1470		}
1471
1472		bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
1473		{
1474			FLAC__ASSERT(is_valid());
1475			return (bool)::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
1476		}
1477
1478		void Chain::merge_padding()
1479		{
1480			FLAC__ASSERT(is_valid());
1481			::FLAC__metadata_chain_merge_padding(chain_);
1482		}
1483
1484		void Chain::sort_padding()
1485		{
1486			FLAC__ASSERT(is_valid());
1487			::FLAC__metadata_chain_sort_padding(chain_);
1488		}
1489
1490
1491		Iterator::Iterator():
1492		iterator_(::FLAC__metadata_iterator_new())
1493		{ }
1494
1495		Iterator::~Iterator()
1496		{
1497			clear();
1498		}
1499
1500		void Iterator::clear()
1501		{
1502			if(0 != iterator_)
1503				FLAC__metadata_iterator_delete(iterator_);
1504			iterator_ = 0;
1505		}
1506
1507		bool Iterator::is_valid() const
1508		{
1509			return 0 != iterator_;
1510		}
1511
1512		void Iterator::init(Chain &chain)
1513		{
1514			FLAC__ASSERT(is_valid());
1515			FLAC__ASSERT(chain.is_valid());
1516			::FLAC__metadata_iterator_init(iterator_, chain.chain_);
1517		}
1518
1519		bool Iterator::next()
1520		{
1521			FLAC__ASSERT(is_valid());
1522			return (bool)::FLAC__metadata_iterator_next(iterator_);
1523		}
1524
1525		bool Iterator::prev()
1526		{
1527			FLAC__ASSERT(is_valid());
1528			return (bool)::FLAC__metadata_iterator_prev(iterator_);
1529		}
1530
1531		::FLAC__MetadataType Iterator::get_block_type() const
1532		{
1533			FLAC__ASSERT(is_valid());
1534			return ::FLAC__metadata_iterator_get_block_type(iterator_);
1535		}
1536
1537		Prototype *Iterator::get_block()
1538		{
1539			FLAC__ASSERT(is_valid());
1540			Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
1541			if(0 != block)
1542				block->set_reference(true);
1543			return block;
1544		}
1545
1546		bool Iterator::set_block(Prototype *block)
1547		{
1548			FLAC__ASSERT(0 != block);
1549			FLAC__ASSERT(is_valid());
1550			bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
1551			if(ret) {
1552				block->set_reference(true);
1553				delete block;
1554			}
1555			return ret;
1556		}
1557
1558		bool Iterator::delete_block(bool replace_with_padding)
1559		{
1560			FLAC__ASSERT(is_valid());
1561			return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
1562		}
1563
1564		bool Iterator::insert_block_before(Prototype *block)
1565		{
1566			FLAC__ASSERT(0 != block);
1567			FLAC__ASSERT(is_valid());
1568			bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
1569			if(ret) {
1570				block->set_reference(true);
1571				delete block;
1572			}
1573			return ret;
1574		}
1575
1576		bool Iterator::insert_block_after(Prototype *block)
1577		{
1578			FLAC__ASSERT(0 != block);
1579			FLAC__ASSERT(is_valid());
1580			bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1581			if(ret) {
1582				block->set_reference(true);
1583				delete block;
1584			}
1585			return ret;
1586		}
1587
1588	}
1589}
1590