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