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