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