last batch of changes and fixes based on the libFLAC++ unit tests
[platform/upstream/flac.git] / src / libFLAC++ / metadata.cc
1 /* libFLAC++ - Free Lossless Audio Codec library
2  * Copyright (C) 2002  Josh Coalson
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA  02111-1307, USA.
18  */
19
20 #include "FLAC++/metadata.h"
21 #include "FLAC/assert.h"
22 #include <stdlib.h> // for malloc(), free()
23 #include <string.h> // for memcpy() etc.
24
25 namespace FLAC {
26         namespace Metadata {
27
28                 // local utility routines
29
30                 namespace local {
31
32                         Prototype *construct_block(::FLAC__StreamMetadata *object)
33                         {
34                                 Prototype *ret = 0;
35                                 switch(object->type) {
36                                         case FLAC__METADATA_TYPE_STREAMINFO:
37                                                 ret = new StreamInfo(object, /*copy=*/false);
38                                                 break;
39                                         case FLAC__METADATA_TYPE_PADDING:
40                                                 ret = new Padding(object, /*copy=*/false);
41                                                 break;
42                                         case FLAC__METADATA_TYPE_APPLICATION:
43                                                 ret = new Application(object, /*copy=*/false);
44                                                 break;
45                                         case FLAC__METADATA_TYPE_SEEKTABLE:
46                                                 ret = new SeekTable(object, /*copy=*/false);
47                                                 break;
48                                         case FLAC__METADATA_TYPE_VORBIS_COMMENT:
49                                                 ret = new VorbisComment(object, /*copy=*/false);
50                                                 break;
51                                         default:
52                                                 FLAC__ASSERT(0);
53                                                 break;
54                                 }
55                                 return ret;
56                         }
57
58                 };
59
60                 Prototype *clone(const Prototype *object)
61                 {
62                         const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
63                         const Padding *padding = dynamic_cast<const Padding *>(object);
64                         const Application *application = dynamic_cast<const Application *>(object);
65                         const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
66                         const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
67
68                         if(0 != streaminfo)
69                                 return new StreamInfo(*streaminfo);
70                         else if(0 != padding)
71                                 return new Padding(*padding);
72                         else if(0 != application)
73                                 return new Application(*application);
74                         else if(0 != seektable)
75                                 return new SeekTable(*seektable);
76                         else if(0 != vorbiscomment)
77                                 return new VorbisComment(*vorbiscomment);
78                         else {
79                                 FLAC__ASSERT(0);
80                                 return 0;
81                         }
82                 }
83
84                 //
85                 // Prototype
86                 //
87
88                 Prototype::Prototype(const Prototype &object):
89                 object_(::FLAC__metadata_object_clone(object.object_)),
90                 is_reference_(false)
91                 {
92                         FLAC__ASSERT(object.is_valid());
93                 }
94
95                 Prototype::Prototype(const ::FLAC__StreamMetadata &object):
96                 object_(::FLAC__metadata_object_clone(&object)),
97                 is_reference_(false)
98                 {
99                 }
100
101                 Prototype::Prototype(const ::FLAC__StreamMetadata *object):
102                 object_(::FLAC__metadata_object_clone(object)),
103                 is_reference_(false)
104                 {
105                         FLAC__ASSERT(0 != object);
106                 }
107
108                 Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy):
109                 object_(copy? ::FLAC__metadata_object_clone(object) : object),
110                 is_reference_(false)
111                 {
112                         FLAC__ASSERT(0 != object);
113                 }
114
115                 Prototype::~Prototype()
116                 {
117                         clear();
118                 }
119
120                 void Prototype::clear()
121                 {
122                         if(0 != object_ && !is_reference_)
123                                 FLAC__metadata_object_delete(object_);
124                         object_ = 0;
125                 }
126
127                 void Prototype::operator=(const Prototype &object)
128                 {
129                         FLAC__ASSERT(object.is_valid());
130                         clear();
131                         is_reference_ = false;
132                         object_ = ::FLAC__metadata_object_clone(object.object_);
133                 }
134
135                 void Prototype::operator=(const ::FLAC__StreamMetadata &object)
136                 {
137                         clear();
138                         is_reference_ = false;
139                         object_ = ::FLAC__metadata_object_clone(&object);
140                 }
141
142                 void Prototype::operator=(const ::FLAC__StreamMetadata *object)
143                 {
144                         FLAC__ASSERT(0 != object);
145                         clear();
146                         is_reference_ = false;
147                         object_ = ::FLAC__metadata_object_clone(object);
148                 }
149
150                 bool Prototype::get_is_last() const
151                 {
152                         FLAC__ASSERT(is_valid());
153                         return (bool)object_->is_last;
154                 }
155
156                 FLAC__MetadataType Prototype::get_type() const
157                 {
158                         FLAC__ASSERT(is_valid());
159                         return object_->type;
160                 }
161
162                 unsigned Prototype::get_length() const
163                 {
164                         FLAC__ASSERT(is_valid());
165                         return object_->length;
166                 }
167
168                 void Prototype::set_is_last(bool value)
169                 {
170                         FLAC__ASSERT(is_valid());
171                         object_->is_last = value;
172                 }
173
174
175                 //
176                 // StreamInfo
177                 //
178
179                 StreamInfo::StreamInfo():
180                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
181                 { }
182
183                 StreamInfo::~StreamInfo()
184                 { }
185
186                 unsigned StreamInfo::get_min_blocksize() const
187                 {
188                         FLAC__ASSERT(is_valid());
189                         return object_->data.stream_info.min_blocksize;
190                 }
191
192                 unsigned StreamInfo::get_max_blocksize() const
193                 {
194                         FLAC__ASSERT(is_valid());
195                         return object_->data.stream_info.max_blocksize;
196                 }
197
198                 unsigned StreamInfo::get_min_framesize() const
199                 {
200                         FLAC__ASSERT(is_valid());
201                         return object_->data.stream_info.min_framesize;
202                 }
203
204                 unsigned StreamInfo::get_max_framesize() const
205                 {
206                         FLAC__ASSERT(is_valid());
207                         return object_->data.stream_info.max_framesize;
208                 }
209
210                 unsigned StreamInfo::get_sample_rate() const
211                 {
212                         FLAC__ASSERT(is_valid());
213                         return object_->data.stream_info.sample_rate;
214                 }
215
216                 unsigned StreamInfo::get_channels() const
217                 {
218                         FLAC__ASSERT(is_valid());
219                         return object_->data.stream_info.channels;
220                 }
221
222                 unsigned StreamInfo::get_bits_per_sample() const
223                 {
224                         FLAC__ASSERT(is_valid());
225                         return object_->data.stream_info.bits_per_sample;
226                 }
227
228                 FLAC__uint64 StreamInfo::get_total_samples() const
229                 {
230                         FLAC__ASSERT(is_valid());
231                         return object_->data.stream_info.total_samples;
232                 }
233
234                 const FLAC__byte *StreamInfo::get_md5sum() const
235                 {
236                         FLAC__ASSERT(is_valid());
237                         return object_->data.stream_info.md5sum;
238                 }
239
240                 void StreamInfo::set_min_blocksize(unsigned value)
241                 {
242                         FLAC__ASSERT(is_valid());
243                         FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
244                         FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
245                         object_->data.stream_info.min_blocksize = value;
246                 }
247
248                 void StreamInfo::set_max_blocksize(unsigned value)
249                 {
250                         FLAC__ASSERT(is_valid());
251                         FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
252                         FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
253                         object_->data.stream_info.max_blocksize = value;
254                 }
255
256                 void StreamInfo::set_min_framesize(unsigned value)
257                 {
258                         FLAC__ASSERT(is_valid());
259                         FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
260                         object_->data.stream_info.min_framesize = value;
261                 }
262
263                 void StreamInfo::set_max_framesize(unsigned value)
264                 {
265                         FLAC__ASSERT(is_valid());
266                         FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
267                         object_->data.stream_info.max_framesize = value;
268                 }
269
270                 void StreamInfo::set_sample_rate(unsigned value)
271                 {
272                         FLAC__ASSERT(is_valid());
273                         FLAC__ASSERT(FLAC__format_is_valid_sample_rate(value));
274                         object_->data.stream_info.sample_rate = value;
275                 }
276
277                 void StreamInfo::set_channels(unsigned value)
278                 {
279                         FLAC__ASSERT(is_valid());
280                         FLAC__ASSERT(value > 0);
281                         FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
282                         object_->data.stream_info.channels = value;
283                 }
284
285                 void StreamInfo::set_bits_per_sample(unsigned value)
286                 {
287                         FLAC__ASSERT(is_valid());
288                         FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
289                         FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
290                         object_->data.stream_info.bits_per_sample = value;
291                 }
292
293                 void StreamInfo::set_total_samples(FLAC__uint64 value)
294                 {
295                         FLAC__ASSERT(is_valid());
296                         FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
297                         object_->data.stream_info.total_samples = value;
298                 }
299
300                 void StreamInfo::set_md5sum(const FLAC__byte value[16])
301                 {
302                         FLAC__ASSERT(is_valid());
303                         FLAC__ASSERT(0 != value);
304                         memcpy(object_->data.stream_info.md5sum, value, 16);
305                 }
306
307
308                 //
309                 // Padding
310                 //
311
312                 Padding::Padding():
313                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
314                 { }
315
316                 Padding::~Padding()
317                 { }
318
319                 void Padding::set_length(unsigned length)
320                 {
321                         FLAC__ASSERT(is_valid());
322                         object_->length = length;
323                 }
324
325
326                 //
327                 // Application
328                 //
329
330                 Application::Application():
331                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
332                 { }
333
334                 Application::~Application()
335                 { }
336
337                 const FLAC__byte *Application::get_id() const
338                 {
339                         FLAC__ASSERT(is_valid());
340                         return object_->data.application.id;
341                 }
342
343                 const FLAC__byte *Application::get_data() const
344                 {
345                         FLAC__ASSERT(is_valid());
346                         return object_->data.application.data;
347                 }
348
349                 void Application::set_id(const FLAC__byte value[4])
350                 {
351                         FLAC__ASSERT(is_valid());
352                         FLAC__ASSERT(0 != value);
353                         memcpy(object_->data.application.id, value, 4);
354                 }
355
356                 bool Application::set_data(const FLAC__byte *data, unsigned length)
357                 {
358                         FLAC__ASSERT(is_valid());
359                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
360                 }
361
362                 bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
363                 {
364                         FLAC__ASSERT(is_valid());
365                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
366                 }
367
368
369                 //
370                 // SeekTable
371                 //
372
373                 SeekTable::SeekTable():
374                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
375                 { }
376
377                 SeekTable::~SeekTable()
378                 { }
379
380                 unsigned SeekTable::get_num_points() const
381                 {
382                         FLAC__ASSERT(is_valid());
383                         return object_->data.seek_table.num_points;
384                 }
385
386                 ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
387                 {
388                         FLAC__ASSERT(is_valid());
389                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
390                         return object_->data.seek_table.points[index];
391                 }
392
393                 void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
394                 {
395                         FLAC__ASSERT(is_valid());
396                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
397                         ::FLAC__metadata_object_seektable_set_point(object_, index, point);
398                 }
399
400                 bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
401                 {
402                         FLAC__ASSERT(is_valid());
403                         FLAC__ASSERT(index <= object_->data.seek_table.num_points);
404                         return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
405                 }
406
407                 bool SeekTable::delete_point(unsigned index)
408                 {
409                         FLAC__ASSERT(is_valid());
410                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
411                         return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
412                 }
413
414                 bool SeekTable::is_legal() const
415                 {
416                         FLAC__ASSERT(is_valid());
417                         return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
418                 }
419
420
421                 //
422                 // VorbisComment::Entry
423                 //
424
425                 VorbisComment::Entry::Entry()
426                 {
427                         zero();
428                 }
429
430                 VorbisComment::Entry::Entry(const char *field, unsigned field_length)
431                 {
432                         zero();
433                         construct(field, field_length);
434                 }
435
436                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
437                 {
438                         zero();
439                         construct(field_name, field_value, field_value_length);
440                 }
441
442                 VorbisComment::Entry::Entry(const Entry &entry)
443                 {
444                         FLAC__ASSERT(entry.is_valid());
445                         zero();
446                         construct((const char *)entry.entry_.entry, entry.entry_.length);
447                 }
448
449                 void VorbisComment::Entry::operator=(const Entry &entry)
450                 {
451                         FLAC__ASSERT(entry.is_valid());
452                         clear();
453                         construct((const char *)entry.entry_.entry, entry.entry_.length);
454                 }
455
456                 VorbisComment::Entry::~Entry()
457                 {
458                         clear();
459                 }
460
461                 bool VorbisComment::Entry::is_valid() const
462                 {
463                         return is_valid_;
464                 }
465
466                 unsigned VorbisComment::Entry::get_field_length() const
467                 {
468                         FLAC__ASSERT(is_valid());
469                         return entry_.length;
470                 }
471
472                 unsigned VorbisComment::Entry::get_field_name_length() const
473                 {
474                         FLAC__ASSERT(is_valid());
475                         return field_name_length_;
476                 }
477
478                 unsigned VorbisComment::Entry::get_field_value_length() const
479                 {
480                         FLAC__ASSERT(is_valid());
481                         return field_value_length_;
482                 }
483
484                 ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
485                 {
486                         FLAC__ASSERT(is_valid());
487                         return entry_;
488                 }
489
490                 const char *VorbisComment::Entry::get_field() const
491                 {
492                         FLAC__ASSERT(is_valid());
493                         return (const char *)entry_.entry;
494                 }
495
496                 const char *VorbisComment::Entry::get_field_name() const
497                 {
498                         FLAC__ASSERT(is_valid());
499                         return field_name_;
500                 }
501
502                 const char *VorbisComment::Entry::get_field_value() const
503                 {
504                         FLAC__ASSERT(is_valid());
505                         return field_value_;
506                 }
507
508                 bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
509                 {
510                         FLAC__ASSERT(is_valid());
511                         FLAC__ASSERT(0 != field);
512
513                         clear_entry();
514
515                         if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length))) {
516                                 is_valid_ = false;
517                         }
518                         else {
519                                 entry_.length = field_length;
520                                 memcpy(entry_.entry, field, field_length);
521                                 (void) parse_field();
522                         }
523
524                         return is_valid_;
525                 }
526
527                 bool VorbisComment::Entry::set_field_name(const char *field_name)
528                 {
529                         FLAC__ASSERT(is_valid());
530                         FLAC__ASSERT(0 != field_name);
531
532                         clear_field_name();
533
534                         if(0 == (field_name_ = strdup(field_name))) {
535                                 is_valid_ = false;
536                         }
537                         else {
538                                 field_name_length_ = strlen(field_name_);
539                                 compose_field();
540                         }
541
542                         return is_valid_;
543                 }
544
545                 bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
546                 {
547                         FLAC__ASSERT(is_valid());
548                         FLAC__ASSERT(0 != field_value);
549
550                         clear_field_value();
551
552                         if(0 == (field_value_ = (char *)malloc(field_value_length))) {
553                                 is_valid_ = false;
554                         }
555                         else {
556                                 field_value_length_ = field_value_length;
557                                 memcpy(field_value_, field_value, field_value_length);
558                                 compose_field();
559                         }
560
561                         return is_valid_;
562                 }
563
564                 void VorbisComment::Entry::zero()
565                 {
566                         is_valid_ = true;
567                         entry_.length = 0;
568                         entry_.entry = 0;
569                         field_name_ = 0;
570                         field_name_length_ = 0;
571                         field_value_ = 0;
572                         field_value_length_ = 0;
573                 }
574
575                 void VorbisComment::Entry::clear()
576                 {
577                         clear_entry();
578                         clear_field_name();
579                         clear_field_value();
580                         is_valid_ = true;
581                 }
582
583                 void VorbisComment::Entry::clear_entry()
584                 {
585                         if(0 != entry_.entry) {
586                                 free(entry_.entry);
587                                 entry_.entry = 0;
588                                 entry_.length = 0;
589                         }
590                 }
591
592                 void VorbisComment::Entry::clear_field_name()
593                 {
594                         if(0 != field_name_) {
595                                 free(field_name_);
596                                 field_name_ = 0;
597                                 field_name_length_ = 0;
598                         }
599                 }
600
601                 void VorbisComment::Entry::clear_field_value()
602                 {
603                         if(0 != field_value_) {
604                                 free(field_value_);
605                                 field_value_ = 0;
606                                 field_value_length_ = 0;
607                         }
608                 }
609
610                 void VorbisComment::Entry::construct(const char *field, unsigned field_length)
611                 {
612                         if(set_field(field, field_length))
613                                 parse_field();
614                 }
615
616                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
617                 {
618                         if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
619                                 compose_field();
620                 }
621
622                 void VorbisComment::Entry::compose_field()
623                 {
624                         clear_entry();
625
626                         if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_))) {
627                                 is_valid_ = false;
628                         }
629                         else {
630                                 memcpy(entry_.entry, field_name_, field_name_length_);
631                                 entry_.length += field_name_length_;
632                                 memcpy(entry_.entry + entry_.length, "=", 1);
633                                 entry_.length += 1;
634                                 memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
635                                 entry_.length += field_value_length_;
636                                 is_valid_ = true;
637                         }
638                 }
639
640                 void VorbisComment::Entry::parse_field()
641                 {
642                         clear_field_name();
643                         clear_field_value();
644
645                         const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
646
647                         if(0 == p)
648                                 p = (const char *)entry_.entry + entry_.length;
649
650                         field_name_length_ = p - (const char *)entry_.entry;
651                         if(0 == (field_name_ = (char *)malloc(field_name_length_ + 1))) { // +1 for the trailing \0
652                                 is_valid_ = false;
653                                 return;
654                         }
655                         memcpy(field_name_, entry_.entry, field_name_length_);
656                         field_name_[field_name_length_] = '\0';
657
658                         if(entry_.length - field_name_length_ == 0) {
659                                 field_value_length_ = 0;
660                                 if(0 == (field_value_ = (char *)malloc(0))) {
661                                         is_valid_ = false;
662                                         return;
663                                 }
664                         }
665                         else {
666                                 field_value_length_ = entry_.length - field_name_length_ - 1;
667                                 if(0 == (field_value_ = (char *)malloc(field_value_length_))) {
668                                         is_valid_ = false;
669                                         return;
670                                 }
671                                 memcpy(field_value_, ++p, field_value_length_);
672                         }
673
674                         is_valid_ = true;
675                 }
676
677
678                 //
679                 // VorbisComment
680                 //
681
682                 VorbisComment::VorbisComment():
683                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
684                 { }
685
686                 VorbisComment::~VorbisComment()
687                 { }
688
689                 unsigned VorbisComment::get_num_comments() const
690                 {
691                         FLAC__ASSERT(is_valid());
692                         return object_->data.vorbis_comment.num_comments;
693                 }
694
695                 VorbisComment::Entry VorbisComment::get_vendor_string() const
696                 {
697                         FLAC__ASSERT(is_valid());
698                         return Entry((const char *)object_->data.vorbis_comment.vendor_string.entry, object_->data.vorbis_comment.vendor_string.length);
699                 }
700
701                 VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
702                 {
703                         FLAC__ASSERT(is_valid());
704                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
705                         return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
706                 }
707
708                 bool VorbisComment::set_vendor_string(const VorbisComment::Entry &entry)
709                 {
710                         FLAC__ASSERT(is_valid());
711                         // vendor_string is a special kind of entry
712                         ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
713                         vendor_string.length = entry.get_field_name_length();
714                         vendor_string.entry = (FLAC__byte*)entry.get_field_name(); // we can cheat on const-ness because we make a copy below:
715                         return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
716                 }
717
718                 bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
719                 {
720                         FLAC__ASSERT(is_valid());
721                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
722                         return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
723                 }
724
725                 bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
726                 {
727                         FLAC__ASSERT(is_valid());
728                         FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
729                         return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
730                 }
731
732                 bool VorbisComment::delete_comment(unsigned index)
733                 {
734                         FLAC__ASSERT(is_valid());
735                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
736                         return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
737                 }
738
739
740                 // ============================================================
741                 //
742                 //  Level 0
743                 //
744                 // ============================================================
745
746                 bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
747                 {
748                         FLAC__ASSERT(0 != filename);
749
750                         ::FLAC__StreamMetadata s;
751
752                         if(::FLAC__metadata_get_streaminfo(filename, &s)) {
753                                 streaminfo = s;
754                                 return true;
755                         }
756                         else
757                                 return false;
758                 }
759
760
761                 // ============================================================
762                 //
763                 //  Level 1
764                 //
765                 // ============================================================
766
767                 SimpleIterator::SimpleIterator():
768                 iterator_(::FLAC__metadata_simple_iterator_new())
769                 { }
770
771                 SimpleIterator::~SimpleIterator()
772                 {
773                         clear();
774                 }
775
776                 void SimpleIterator::clear()
777                 {
778                         if(0 != iterator_)
779                                 FLAC__metadata_simple_iterator_delete(iterator_);
780                         iterator_ = 0;
781                 }
782
783                 bool SimpleIterator::init(const char *filename, bool preserve_file_stats)
784                 {
785                         FLAC__ASSERT(0 != filename);
786                         FLAC__ASSERT(is_valid());
787                         return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, preserve_file_stats);
788                 }
789
790                 bool SimpleIterator::is_valid() const
791                 {
792                         return 0 != iterator_;
793                 }
794
795                 SimpleIterator::Status SimpleIterator::status()
796                 {
797                         FLAC__ASSERT(is_valid());
798                         return Status(::FLAC__metadata_simple_iterator_status(iterator_));
799                 }
800
801                 bool SimpleIterator::is_writable() const
802                 {
803                         FLAC__ASSERT(is_valid());
804                         return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
805                 }
806
807                 bool SimpleIterator::next()
808                 {
809                         FLAC__ASSERT(is_valid());
810                         return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
811                 }
812
813                 bool SimpleIterator::prev()
814                 {
815                         FLAC__ASSERT(is_valid());
816                         return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
817                 }
818
819                 ::FLAC__MetadataType SimpleIterator::get_block_type() const
820                 {
821                         FLAC__ASSERT(is_valid());
822                         return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
823                 }
824
825                 Prototype *SimpleIterator::get_block()
826                 {
827                         FLAC__ASSERT(is_valid());
828                         return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
829                 }
830
831                 bool SimpleIterator::set_block(Prototype *block, bool use_padding)
832                 {
833                         FLAC__ASSERT(0 != block);
834                         FLAC__ASSERT(is_valid());
835                         return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
836                 }
837
838                 bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
839                 {
840                         FLAC__ASSERT(0 != block);
841                         FLAC__ASSERT(is_valid());
842                         return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
843                 }
844
845                 bool SimpleIterator::delete_block(bool use_padding)
846                 {
847                         FLAC__ASSERT(is_valid());
848                         return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
849                 }
850
851
852                 // ============================================================
853                 //
854                 //  Level 2
855                 //
856                 // ============================================================
857
858                 Chain::Chain():
859                 chain_(::FLAC__metadata_chain_new())
860                 { }
861
862                 Chain::~Chain()
863                 {
864                         clear();
865                 }
866
867                 void Chain::clear()
868                 {
869                         if(0 != chain_)
870                                 FLAC__metadata_chain_delete(chain_);
871                         chain_ = 0;
872                 }
873
874                 bool Chain::is_valid() const
875                 {
876                         return 0 != chain_;
877                 }
878
879                 Chain::Status Chain::status()
880                 {
881                         FLAC__ASSERT(is_valid());
882                         return Status(::FLAC__metadata_chain_status(chain_));
883                 }
884
885                 bool Chain::read(const char *filename)
886                 {
887                         FLAC__ASSERT(0 != filename);
888                         FLAC__ASSERT(is_valid());
889                         return (bool)::FLAC__metadata_chain_read(chain_, filename);
890                 }
891
892                 bool Chain::write(bool use_padding, bool preserve_file_stats)
893                 {
894                         FLAC__ASSERT(is_valid());
895                         return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
896                 }
897
898                 void Chain::merge_padding()
899                 {
900                         FLAC__ASSERT(is_valid());
901                         ::FLAC__metadata_chain_merge_padding(chain_);
902                 }
903
904                 void Chain::sort_padding()
905                 {
906                         FLAC__ASSERT(is_valid());
907                         ::FLAC__metadata_chain_sort_padding(chain_);
908                 }
909
910
911                 Iterator::Iterator():
912                 iterator_(::FLAC__metadata_iterator_new())
913                 { }
914
915                 Iterator::~Iterator()
916                 {
917                         clear();
918                 }
919
920                 void Iterator::clear()
921                 {
922                         if(0 != iterator_)
923                                 FLAC__metadata_iterator_delete(iterator_);
924                         iterator_ = 0;
925                 }
926
927                 bool Iterator::is_valid() const
928                 {
929                         return 0 != iterator_;
930                 }
931
932                 void Iterator::init(Chain &chain)
933                 {
934                         FLAC__ASSERT(is_valid());
935                         FLAC__ASSERT(chain.is_valid());
936                         ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
937                 }
938
939                 bool Iterator::next()
940                 {
941                         FLAC__ASSERT(is_valid());
942                         return (bool)::FLAC__metadata_iterator_next(iterator_);
943                 }
944
945                 bool Iterator::prev()
946                 {
947                         FLAC__ASSERT(is_valid());
948                         return (bool)::FLAC__metadata_iterator_prev(iterator_);
949                 }
950
951                 ::FLAC__MetadataType Iterator::get_block_type() const 
952                 {
953                         FLAC__ASSERT(is_valid());
954                         return ::FLAC__metadata_iterator_get_block_type(iterator_);
955                 }
956
957                 Prototype *Iterator::get_block()
958                 {
959                         FLAC__ASSERT(is_valid());
960                         Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
961                         if(0 != block)
962                                 block->set_reference(true);
963                         return block;
964                 }
965
966                 bool Iterator::set_block(Prototype *block)
967                 {
968                         FLAC__ASSERT(0 != block);
969                         FLAC__ASSERT(is_valid());
970                         bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
971                         if(ret) {
972                                 block->set_reference(true);
973                                 delete block;
974                         }
975                         return ret;
976                 }
977
978                 bool Iterator::delete_block(bool replace_with_padding)
979                 {
980                         FLAC__ASSERT(is_valid());
981                         return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
982                 }
983
984                 bool Iterator::insert_block_before(Prototype *block)
985                 {
986                         FLAC__ASSERT(0 != block);
987                         FLAC__ASSERT(is_valid());
988                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
989                         if(ret) {
990                                 block->set_reference(true);
991                                 delete block;
992                         }
993                         return ret;
994                 }
995
996                 bool Iterator::insert_block_after(Prototype *block)
997                 {
998                         FLAC__ASSERT(0 != block);
999                         FLAC__ASSERT(is_valid());
1000                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1001                         if(ret) {
1002                                 block->set_reference(true);
1003                                 delete block;
1004                         }
1005                         return ret;
1006                 }
1007
1008         };
1009 };