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