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