0870d029d8bd49ec4c54860b3bb38d70cb9a5aed
[platform/upstream/flac.git] / src / libFLAC++ / metadata.cpp
1 /* libFLAC++ - Free Lossless Audio Codec library
2  * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Josh Coalson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of the Xiph.org Foundation nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #define __STDC_LIMIT_MACROS 1 /* otherwise SIZE_MAX is not defined for c++ */
33 #include "share/alloc.h"
34 #include "FLAC++/metadata.h"
35 #include "FLAC/assert.h"
36 #include <stdlib.h> // for malloc(), free()
37 #include <string.h> // for memcpy() etc.
38
39 #ifdef _MSC_VER
40 // warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
41 #pragma warning ( disable : 4800 )
42 #endif
43
44 namespace FLAC {
45         namespace Metadata {
46
47                 // local utility routines
48
49                 namespace local {
50
51                         Prototype *construct_block(::FLAC__StreamMetadata *object)
52                         {
53                                 Prototype *ret = 0;
54                                 switch(object->type) {
55                                         case FLAC__METADATA_TYPE_STREAMINFO:
56                                                 ret = new StreamInfo(object, /*copy=*/false);
57                                                 break;
58                                         case FLAC__METADATA_TYPE_PADDING:
59                                                 ret = new Padding(object, /*copy=*/false);
60                                                 break;
61                                         case FLAC__METADATA_TYPE_APPLICATION:
62                                                 ret = new Application(object, /*copy=*/false);
63                                                 break;
64                                         case FLAC__METADATA_TYPE_SEEKTABLE:
65                                                 ret = new SeekTable(object, /*copy=*/false);
66                                                 break;
67                                         case FLAC__METADATA_TYPE_VORBIS_COMMENT:
68                                                 ret = new VorbisComment(object, /*copy=*/false);
69                                                 break;
70                                         case FLAC__METADATA_TYPE_CUESHEET:
71                                                 ret = new CueSheet(object, /*copy=*/false);
72                                                 break;
73                                         case FLAC__METADATA_TYPE_PICTURE:
74                                                 ret = new Picture(object, /*copy=*/false);
75                                                 break;
76                                         default:
77                                                 ret = new Unknown(object, /*copy=*/false);
78                                                 break;
79                                 }
80                                 return ret;
81                         }
82
83                 }
84
85                 FLACPP_API Prototype *clone(const Prototype *object)
86                 {
87                         FLAC__ASSERT(0 != object);
88
89                         const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
90                         const Padding *padding = dynamic_cast<const Padding *>(object);
91                         const Application *application = dynamic_cast<const Application *>(object);
92                         const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
93                         const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
94                         const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
95                         const Picture *picture = dynamic_cast<const Picture *>(object);
96                         const Unknown *unknown = dynamic_cast<const Unknown *>(object);
97
98                         if(0 != streaminfo)
99                                 return new StreamInfo(*streaminfo);
100                         else if(0 != padding)
101                                 return new Padding(*padding);
102                         else if(0 != application)
103                                 return new Application(*application);
104                         else if(0 != seektable)
105                                 return new SeekTable(*seektable);
106                         else if(0 != vorbiscomment)
107                                 return new VorbisComment(*vorbiscomment);
108                         else if(0 != cuesheet)
109                                 return new CueSheet(*cuesheet);
110                         else if(0 != picture)
111                                 return new Picture(*picture);
112                         else if(0 != unknown)
113                                 return new Unknown(*unknown);
114                         else {
115                                 FLAC__ASSERT(0);
116                                 return 0;
117                         }
118                 }
119
120                 //
121                 // Prototype
122                 //
123
124                 Prototype::Prototype(const Prototype &object):
125                 object_(::FLAC__metadata_object_clone(object.object_)),
126                 is_reference_(false)
127                 {
128                         FLAC__ASSERT(object.is_valid());
129                 }
130
131                 Prototype::Prototype(const ::FLAC__StreamMetadata &object):
132                 object_(::FLAC__metadata_object_clone(&object)),
133                 is_reference_(false)
134                 {
135                 }
136
137                 Prototype::Prototype(const ::FLAC__StreamMetadata *object):
138                 object_(::FLAC__metadata_object_clone(object)),
139                 is_reference_(false)
140                 {
141                         FLAC__ASSERT(0 != object);
142                 }
143
144                 Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy):
145                 object_(copy? ::FLAC__metadata_object_clone(object) : object),
146                 is_reference_(false)
147                 {
148                         FLAC__ASSERT(0 != object);
149                 }
150
151                 Prototype::~Prototype()
152                 {
153                         clear();
154                 }
155
156                 void Prototype::clear()
157                 {
158                         if(0 != object_ && !is_reference_)
159                                 FLAC__metadata_object_delete(object_);
160                         object_ = 0;
161                 }
162
163                 Prototype &Prototype::operator=(const Prototype &object)
164                 {
165                         FLAC__ASSERT(object.is_valid());
166                         clear();
167                         is_reference_ = false;
168                         object_ = ::FLAC__metadata_object_clone(object.object_);
169                         return *this;
170                 }
171
172                 Prototype &Prototype::operator=(const ::FLAC__StreamMetadata &object)
173                 {
174                         clear();
175                         is_reference_ = false;
176                         object_ = ::FLAC__metadata_object_clone(&object);
177                         return *this;
178                 }
179
180                 Prototype &Prototype::operator=(const ::FLAC__StreamMetadata *object)
181                 {
182                         FLAC__ASSERT(0 != object);
183                         clear();
184                         is_reference_ = false;
185                         object_ = ::FLAC__metadata_object_clone(object);
186                         return *this;
187                 }
188
189                 Prototype &Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy)
190                 {
191                         FLAC__ASSERT(0 != object);
192                         clear();
193                         object_ = (copy? ::FLAC__metadata_object_clone(object) : object);
194                         is_reference_ = false;
195                         return *this;
196                 }
197
198                 bool Prototype::get_is_last() const
199                 {
200                         FLAC__ASSERT(is_valid());
201                         return (bool)object_->is_last;
202                 }
203
204                 FLAC__MetadataType Prototype::get_type() const
205                 {
206                         FLAC__ASSERT(is_valid());
207                         return object_->type;
208                 }
209
210                 unsigned Prototype::get_length() const
211                 {
212                         FLAC__ASSERT(is_valid());
213                         return object_->length;
214                 }
215
216                 void Prototype::set_is_last(bool value)
217                 {
218                         FLAC__ASSERT(is_valid());
219                         object_->is_last = value;
220                 }
221
222
223                 //
224                 // StreamInfo
225                 //
226
227                 StreamInfo::StreamInfo():
228                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
229                 { }
230
231                 StreamInfo::~StreamInfo()
232                 { }
233
234                 unsigned StreamInfo::get_min_blocksize() const
235                 {
236                         FLAC__ASSERT(is_valid());
237                         return object_->data.stream_info.min_blocksize;
238                 }
239
240                 unsigned StreamInfo::get_max_blocksize() const
241                 {
242                         FLAC__ASSERT(is_valid());
243                         return object_->data.stream_info.max_blocksize;
244                 }
245
246                 unsigned StreamInfo::get_min_framesize() const
247                 {
248                         FLAC__ASSERT(is_valid());
249                         return object_->data.stream_info.min_framesize;
250                 }
251
252                 unsigned StreamInfo::get_max_framesize() const
253                 {
254                         FLAC__ASSERT(is_valid());
255                         return object_->data.stream_info.max_framesize;
256                 }
257
258                 unsigned StreamInfo::get_sample_rate() const
259                 {
260                         FLAC__ASSERT(is_valid());
261                         return object_->data.stream_info.sample_rate;
262                 }
263
264                 unsigned StreamInfo::get_channels() const
265                 {
266                         FLAC__ASSERT(is_valid());
267                         return object_->data.stream_info.channels;
268                 }
269
270                 unsigned StreamInfo::get_bits_per_sample() const
271                 {
272                         FLAC__ASSERT(is_valid());
273                         return object_->data.stream_info.bits_per_sample;
274                 }
275
276                 FLAC__uint64 StreamInfo::get_total_samples() const
277                 {
278                         FLAC__ASSERT(is_valid());
279                         return object_->data.stream_info.total_samples;
280                 }
281
282                 const FLAC__byte *StreamInfo::get_md5sum() const
283                 {
284                         FLAC__ASSERT(is_valid());
285                         return object_->data.stream_info.md5sum;
286                 }
287
288                 void StreamInfo::set_min_blocksize(unsigned value)
289                 {
290                         FLAC__ASSERT(is_valid());
291                         FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
292                         FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
293                         object_->data.stream_info.min_blocksize = value;
294                 }
295
296                 void StreamInfo::set_max_blocksize(unsigned value)
297                 {
298                         FLAC__ASSERT(is_valid());
299                         FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
300                         FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
301                         object_->data.stream_info.max_blocksize = value;
302                 }
303
304                 void StreamInfo::set_min_framesize(unsigned value)
305                 {
306                         FLAC__ASSERT(is_valid());
307                         FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
308                         object_->data.stream_info.min_framesize = value;
309                 }
310
311                 void StreamInfo::set_max_framesize(unsigned value)
312                 {
313                         FLAC__ASSERT(is_valid());
314                         FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
315                         object_->data.stream_info.max_framesize = value;
316                 }
317
318                 void StreamInfo::set_sample_rate(unsigned value)
319                 {
320                         FLAC__ASSERT(is_valid());
321                         FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
322                         object_->data.stream_info.sample_rate = value;
323                 }
324
325                 void StreamInfo::set_channels(unsigned value)
326                 {
327                         FLAC__ASSERT(is_valid());
328                         FLAC__ASSERT(value > 0);
329                         FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
330                         object_->data.stream_info.channels = value;
331                 }
332
333                 void StreamInfo::set_bits_per_sample(unsigned value)
334                 {
335                         FLAC__ASSERT(is_valid());
336                         FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
337                         FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
338                         object_->data.stream_info.bits_per_sample = value;
339                 }
340
341                 void StreamInfo::set_total_samples(FLAC__uint64 value)
342                 {
343                         FLAC__ASSERT(is_valid());
344                         FLAC__ASSERT(value < (((FLAC__uint64)1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
345                         object_->data.stream_info.total_samples = value;
346                 }
347
348                 void StreamInfo::set_md5sum(const FLAC__byte value[16])
349                 {
350                         FLAC__ASSERT(is_valid());
351                         FLAC__ASSERT(0 != value);
352                         memcpy(object_->data.stream_info.md5sum, value, 16);
353                 }
354
355
356                 //
357                 // Padding
358                 //
359
360                 Padding::Padding():
361                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
362                 { }
363
364                 Padding::~Padding()
365                 { }
366
367                 void Padding::set_length(unsigned length)
368                 {
369                         FLAC__ASSERT(is_valid());
370                         object_->length = length;
371                 }
372
373
374                 //
375                 // Application
376                 //
377
378                 Application::Application():
379                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
380                 { }
381
382                 Application::~Application()
383                 { }
384
385                 const FLAC__byte *Application::get_id() const
386                 {
387                         FLAC__ASSERT(is_valid());
388                         return object_->data.application.id;
389                 }
390
391                 const FLAC__byte *Application::get_data() const
392                 {
393                         FLAC__ASSERT(is_valid());
394                         return object_->data.application.data;
395                 }
396
397                 void Application::set_id(const FLAC__byte value[4])
398                 {
399                         FLAC__ASSERT(is_valid());
400                         FLAC__ASSERT(0 != value);
401                         memcpy(object_->data.application.id, value, 4);
402                 }
403
404                 bool Application::set_data(const FLAC__byte *data, unsigned length)
405                 {
406                         FLAC__ASSERT(is_valid());
407                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
408                 }
409
410                 bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
411                 {
412                         FLAC__ASSERT(is_valid());
413                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
414                 }
415
416
417                 //
418                 // SeekTable
419                 //
420
421                 SeekTable::SeekTable():
422                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
423                 { }
424
425                 SeekTable::~SeekTable()
426                 { }
427
428                 unsigned SeekTable::get_num_points() const
429                 {
430                         FLAC__ASSERT(is_valid());
431                         return object_->data.seek_table.num_points;
432                 }
433
434                 ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
435                 {
436                         FLAC__ASSERT(is_valid());
437                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
438                         return object_->data.seek_table.points[index];
439                 }
440
441                 bool SeekTable::resize_points(unsigned new_num_points)
442                 {
443                         FLAC__ASSERT(is_valid());
444                         return (bool)::FLAC__metadata_object_seektable_resize_points(object_, new_num_points);
445                 }
446
447                 void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
448                 {
449                         FLAC__ASSERT(is_valid());
450                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
451                         ::FLAC__metadata_object_seektable_set_point(object_, index, point);
452                 }
453
454                 bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
455                 {
456                         FLAC__ASSERT(is_valid());
457                         FLAC__ASSERT(index <= object_->data.seek_table.num_points);
458                         return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
459                 }
460
461                 bool SeekTable::delete_point(unsigned index)
462                 {
463                         FLAC__ASSERT(is_valid());
464                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
465                         return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
466                 }
467
468                 bool SeekTable::is_legal() const
469                 {
470                         FLAC__ASSERT(is_valid());
471                         return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
472                 }
473
474                 bool SeekTable::template_append_placeholders(unsigned num)
475                 {
476                         FLAC__ASSERT(is_valid());
477                         return (bool)::FLAC__metadata_object_seektable_template_append_placeholders(object_, num);
478                 }
479
480                 bool SeekTable::template_append_point(FLAC__uint64 sample_number)
481                 {
482                         FLAC__ASSERT(is_valid());
483                         return (bool)::FLAC__metadata_object_seektable_template_append_point(object_, sample_number);
484                 }
485
486                 bool SeekTable::template_append_points(FLAC__uint64 sample_numbers[], unsigned num)
487                 {
488                         FLAC__ASSERT(is_valid());
489                         return (bool)::FLAC__metadata_object_seektable_template_append_points(object_, sample_numbers, num);
490                 }
491
492                 bool SeekTable::template_append_spaced_points(unsigned num, FLAC__uint64 total_samples)
493                 {
494                         FLAC__ASSERT(is_valid());
495                         return (bool)::FLAC__metadata_object_seektable_template_append_spaced_points(object_, num, total_samples);
496                 }
497
498                 bool SeekTable::template_append_spaced_points_by_samples(unsigned samples, FLAC__uint64 total_samples)
499                 {
500                         FLAC__ASSERT(is_valid());
501                         return (bool)::FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(object_, samples, total_samples);
502                 }
503
504                 bool SeekTable::template_sort(bool compact)
505                 {
506                         FLAC__ASSERT(is_valid());
507                         return (bool)::FLAC__metadata_object_seektable_template_sort(object_, compact);
508                 }
509
510
511                 //
512                 // VorbisComment::Entry
513                 //
514
515                 VorbisComment::Entry::Entry()
516                 {
517                         zero();
518                 }
519
520                 VorbisComment::Entry::Entry(const char *field, unsigned field_length)
521                 {
522                         zero();
523                         construct(field, field_length);
524                 }
525
526                 VorbisComment::Entry::Entry(const char *field)
527                 {
528                         zero();
529                         construct(field);
530                 }
531
532                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
533                 {
534                         zero();
535                         construct(field_name, field_value, field_value_length);
536                 }
537
538                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value)
539                 {
540                         zero();
541                         construct(field_name, field_value);
542                 }
543
544                 VorbisComment::Entry::Entry(const Entry &entry)
545                 {
546                         FLAC__ASSERT(entry.is_valid());
547                         zero();
548                         construct((const char *)entry.entry_.entry, entry.entry_.length);
549                 }
550
551                 VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
552                 {
553                         FLAC__ASSERT(entry.is_valid());
554                         clear();
555                         construct((const char *)entry.entry_.entry, entry.entry_.length);
556                         return *this;
557                 }
558
559                 VorbisComment::Entry::~Entry()
560                 {
561                         clear();
562                 }
563
564                 bool VorbisComment::Entry::is_valid() const
565                 {
566                         return is_valid_;
567                 }
568
569                 unsigned VorbisComment::Entry::get_field_length() const
570                 {
571                         FLAC__ASSERT(is_valid());
572                         return entry_.length;
573                 }
574
575                 unsigned VorbisComment::Entry::get_field_name_length() const
576                 {
577                         FLAC__ASSERT(is_valid());
578                         return field_name_length_;
579                 }
580
581                 unsigned VorbisComment::Entry::get_field_value_length() const
582                 {
583                         FLAC__ASSERT(is_valid());
584                         return field_value_length_;
585                 }
586
587                 ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
588                 {
589                         FLAC__ASSERT(is_valid());
590                         return entry_;
591                 }
592
593                 const char *VorbisComment::Entry::get_field() const
594                 {
595                         FLAC__ASSERT(is_valid());
596                         return (const char *)entry_.entry;
597                 }
598
599                 const char *VorbisComment::Entry::get_field_name() const
600                 {
601                         FLAC__ASSERT(is_valid());
602                         return field_name_;
603                 }
604
605                 const char *VorbisComment::Entry::get_field_value() const
606                 {
607                         FLAC__ASSERT(is_valid());
608                         return field_value_;
609                 }
610
611                 bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
612                 {
613                         FLAC__ASSERT(is_valid());
614                         FLAC__ASSERT(0 != field);
615
616                         if(!::FLAC__format_vorbiscomment_entry_is_legal((const ::FLAC__byte*)field, field_length))
617                                 return is_valid_ = false;
618
619                         clear_entry();
620
621                         if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_2op_(field_length, /*+*/1))) {
622                                 is_valid_ = false;
623                         }
624                         else {
625                                 entry_.length = field_length;
626                                 memcpy(entry_.entry, field, field_length);
627                                 entry_.entry[field_length] = '\0';
628                                 (void) parse_field();
629                         }
630
631                         return is_valid_;
632                 }
633
634                 bool VorbisComment::Entry::set_field(const char *field)
635                 {
636                         return set_field(field, strlen(field));
637                 }
638
639                 bool VorbisComment::Entry::set_field_name(const char *field_name)
640                 {
641                         FLAC__ASSERT(is_valid());
642                         FLAC__ASSERT(0 != field_name);
643
644                         if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
645                                 return is_valid_ = false;
646
647                         clear_field_name();
648
649                         if(0 == (field_name_ = strdup(field_name))) {
650                                 is_valid_ = false;
651                         }
652                         else {
653                                 field_name_length_ = strlen(field_name_);
654                                 compose_field();
655                         }
656
657                         return is_valid_;
658                 }
659
660                 bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
661                 {
662                         FLAC__ASSERT(is_valid());
663                         FLAC__ASSERT(0 != field_value);
664
665                         if(!::FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte*)field_value, field_value_length))
666                                 return is_valid_ = false;
667
668                         clear_field_value();
669
670                         if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length, /*+*/1))) {
671                                 is_valid_ = false;
672                         }
673                         else {
674                                 field_value_length_ = field_value_length;
675                                 memcpy(field_value_, field_value, field_value_length);
676                                 field_value_[field_value_length] = '\0';
677                                 compose_field();
678                         }
679
680                         return is_valid_;
681                 }
682
683                 bool VorbisComment::Entry::set_field_value(const char *field_value)
684                 {
685                         return set_field_value(field_value, strlen(field_value));
686                 }
687
688                 void VorbisComment::Entry::zero()
689                 {
690                         is_valid_ = true;
691                         entry_.length = 0;
692                         entry_.entry = 0;
693                         field_name_ = 0;
694                         field_name_length_ = 0;
695                         field_value_ = 0;
696                         field_value_length_ = 0;
697                 }
698
699                 void VorbisComment::Entry::clear()
700                 {
701                         clear_entry();
702                         clear_field_name();
703                         clear_field_value();
704                         is_valid_ = true;
705                 }
706
707                 void VorbisComment::Entry::clear_entry()
708                 {
709                         if(0 != entry_.entry) {
710                                 free(entry_.entry);
711                                 entry_.entry = 0;
712                                 entry_.length = 0;
713                         }
714                 }
715
716                 void VorbisComment::Entry::clear_field_name()
717                 {
718                         if(0 != field_name_) {
719                                 free(field_name_);
720                                 field_name_ = 0;
721                                 field_name_length_ = 0;
722                         }
723                 }
724
725                 void VorbisComment::Entry::clear_field_value()
726                 {
727                         if(0 != field_value_) {
728                                 free(field_value_);
729                                 field_value_ = 0;
730                                 field_value_length_ = 0;
731                         }
732                 }
733
734                 void VorbisComment::Entry::construct(const char *field, unsigned field_length)
735                 {
736                         if(set_field(field, field_length))
737                                 parse_field();
738                 }
739
740                 void VorbisComment::Entry::construct(const char *field)
741                 {
742                         construct(field, strlen(field));
743                 }
744
745                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
746                 {
747                         if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
748                                 compose_field();
749                 }
750
751                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
752                 {
753                         construct(field_name, field_value, strlen(field_value));
754                 }
755
756                 void VorbisComment::Entry::compose_field()
757                 {
758                         clear_entry();
759
760                         if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1))) {
761                                 is_valid_ = false;
762                         }
763                         else {
764                                 memcpy(entry_.entry, field_name_, field_name_length_);
765                                 entry_.length += field_name_length_;
766                                 memcpy(entry_.entry + entry_.length, "=", 1);
767                                 entry_.length += 1;
768                                 memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
769                                 entry_.length += field_value_length_;
770                                 entry_.entry[entry_.length] = '\0';
771                                 is_valid_ = true;
772                         }
773                 }
774
775                 void VorbisComment::Entry::parse_field()
776                 {
777                         clear_field_name();
778                         clear_field_value();
779
780                         const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
781
782                         if(0 == p)
783                                 p = (const char *)entry_.entry + entry_.length;
784
785                         field_name_length_ = (unsigned)(p - (const char *)entry_.entry);
786                         if(0 == (field_name_ = (char *)safe_malloc_add_2op_(field_name_length_, /*+*/1))) { // +1 for the trailing \0
787                                 is_valid_ = false;
788                                 return;
789                         }
790                         memcpy(field_name_, entry_.entry, field_name_length_);
791                         field_name_[field_name_length_] = '\0';
792
793                         if(entry_.length - field_name_length_ == 0) {
794                                 field_value_length_ = 0;
795                                 if(0 == (field_value_ = (char *)safe_malloc_(0))) {
796                                         is_valid_ = false;
797                                         return;
798                                 }
799                         }
800                         else {
801                                 field_value_length_ = entry_.length - field_name_length_ - 1;
802                                 if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length_, /*+*/1))) { // +1 for the trailing \0
803                                         is_valid_ = false;
804                                         return;
805                                 }
806                                 memcpy(field_value_, ++p, field_value_length_);
807                                 field_value_[field_value_length_] = '\0';
808                         }
809
810                         is_valid_ = true;
811                 }
812
813
814                 //
815                 // VorbisComment
816                 //
817
818                 VorbisComment::VorbisComment():
819                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
820                 { }
821
822                 VorbisComment::~VorbisComment()
823                 { }
824
825                 unsigned VorbisComment::get_num_comments() const
826                 {
827                         FLAC__ASSERT(is_valid());
828                         return object_->data.vorbis_comment.num_comments;
829                 }
830
831                 const FLAC__byte *VorbisComment::get_vendor_string() const
832                 {
833                         FLAC__ASSERT(is_valid());
834                         return object_->data.vorbis_comment.vendor_string.entry;
835                 }
836
837                 VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
838                 {
839                         FLAC__ASSERT(is_valid());
840                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
841                         return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
842                 }
843
844                 bool VorbisComment::set_vendor_string(const FLAC__byte *string)
845                 {
846                         FLAC__ASSERT(is_valid());
847                         // vendor_string is a special kind of entry
848                         const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { strlen((const char *)string), (FLAC__byte*)string }; // we can cheat on const-ness because we make a copy below:
849                         return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
850                 }
851
852                 bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
853                 {
854                         FLAC__ASSERT(is_valid());
855                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
856                         return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
857                 }
858
859                 bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
860                 {
861                         FLAC__ASSERT(is_valid());
862                         FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
863                         return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
864                 }
865
866                 bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
867                 {
868                         FLAC__ASSERT(is_valid());
869                         return (bool)::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true);
870                 }
871
872                 bool VorbisComment::delete_comment(unsigned index)
873                 {
874                         FLAC__ASSERT(is_valid());
875                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
876                         return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
877                 }
878
879
880                 //
881                 // CueSheet::Track
882                 //
883
884                 CueSheet::Track::Track():
885                 object_(::FLAC__metadata_object_cuesheet_track_new())
886                 { }
887
888                 CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track):
889                 object_(::FLAC__metadata_object_cuesheet_track_clone(track))
890                 { }
891
892                 CueSheet::Track::Track(const Track &track):
893                 object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_))
894                 { }
895
896                 CueSheet::Track &CueSheet::Track::operator=(const Track &track)
897                 {
898                         if(0 != object_)
899                                 ::FLAC__metadata_object_cuesheet_track_delete(object_);
900                         object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_);
901                         return *this;
902                 }
903
904                 CueSheet::Track::~Track()
905                 {
906                         if(0 != object_)
907                                 ::FLAC__metadata_object_cuesheet_track_delete(object_);
908                 }
909
910                 bool CueSheet::Track::is_valid() const
911                 {
912                         return(0 != object_);
913                 }
914
915                 ::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(unsigned i) const
916                 {
917                         FLAC__ASSERT(is_valid());
918                         FLAC__ASSERT(i < object_->num_indices);
919                         return object_->indices[i];
920                 }
921
922                 void CueSheet::Track::set_isrc(const char value[12])
923                 {
924                         FLAC__ASSERT(is_valid());
925                         FLAC__ASSERT(0 != value);
926                         memcpy(object_->isrc, value, 12);
927                         object_->isrc[12] = '\0';
928                 }
929
930                 void CueSheet::Track::set_type(unsigned value)
931                 {
932                         FLAC__ASSERT(is_valid());
933                         FLAC__ASSERT(value <= 1);
934                         object_->type = value;
935                 }
936
937                 void CueSheet::Track::set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index)
938                 {
939                         FLAC__ASSERT(is_valid());
940                         FLAC__ASSERT(i < object_->num_indices);
941                         object_->indices[i] = index;
942                 }
943
944
945                 //
946                 // CueSheet
947                 //
948
949                 CueSheet::CueSheet():
950                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false)
951                 { }
952
953                 CueSheet::~CueSheet()
954                 { }
955
956                 const char *CueSheet::get_media_catalog_number() const
957                 {
958                         FLAC__ASSERT(is_valid());
959                         return object_->data.cue_sheet.media_catalog_number;
960                 }
961
962                 FLAC__uint64 CueSheet::get_lead_in() const
963                 {
964                         FLAC__ASSERT(is_valid());
965                         return object_->data.cue_sheet.lead_in;
966                 }
967
968                 bool CueSheet::get_is_cd() const
969                 {
970                         FLAC__ASSERT(is_valid());
971                         return object_->data.cue_sheet.is_cd? true : false;
972                 }
973
974                 unsigned CueSheet::get_num_tracks() const
975                 {
976                         FLAC__ASSERT(is_valid());
977                         return object_->data.cue_sheet.num_tracks;
978                 }
979
980                 CueSheet::Track CueSheet::get_track(unsigned i) const
981                 {
982                         FLAC__ASSERT(is_valid());
983                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
984                         return Track(object_->data.cue_sheet.tracks + i);
985                 }
986
987                 void CueSheet::set_media_catalog_number(const char value[128])
988                 {
989                         FLAC__ASSERT(is_valid());
990                         FLAC__ASSERT(0 != value);
991                         memcpy(object_->data.cue_sheet.media_catalog_number, value, 128);
992                         object_->data.cue_sheet.media_catalog_number[128] = '\0';
993                 }
994
995                 void CueSheet::set_lead_in(FLAC__uint64 value)
996                 {
997                         FLAC__ASSERT(is_valid());
998                         object_->data.cue_sheet.lead_in = value;
999                 }
1000
1001                 void CueSheet::set_is_cd(bool value)
1002                 {
1003                         FLAC__ASSERT(is_valid());
1004                         object_->data.cue_sheet.is_cd = value;
1005                 }
1006
1007                 void CueSheet::set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
1008                 {
1009                         FLAC__ASSERT(is_valid());
1010                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
1011                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
1012                         object_->data.cue_sheet.tracks[track_num].indices[index_num] = index;
1013                 }
1014
1015                 bool CueSheet::insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
1016                 {
1017                         FLAC__ASSERT(is_valid());
1018                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
1019                         FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
1020                         return (bool)::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, index);
1021                 }
1022
1023                 bool CueSheet::delete_index(unsigned track_num, unsigned index_num)
1024                 {
1025                         FLAC__ASSERT(is_valid());
1026                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
1027                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
1028                         return (bool)::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num);
1029                 }
1030
1031                 bool CueSheet::set_track(unsigned i, const CueSheet::Track &track)
1032                 {
1033                         FLAC__ASSERT(is_valid());
1034                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1035                         // We can safely const_cast since copy=true
1036                         return (bool)::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
1037                 }
1038
1039                 bool CueSheet::insert_track(unsigned i, const CueSheet::Track &track)
1040                 {
1041                         FLAC__ASSERT(is_valid());
1042                         FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
1043                         // We can safely const_cast since copy=true
1044                         return (bool)::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
1045                 }
1046
1047                 bool CueSheet::delete_track(unsigned i)
1048                 {
1049                         FLAC__ASSERT(is_valid());
1050                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1051                         return (bool)::FLAC__metadata_object_cuesheet_delete_track(object_, i);
1052                 }
1053
1054                 bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
1055                 {
1056                         FLAC__ASSERT(is_valid());
1057                         return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
1058                 }
1059
1060                 FLAC__uint32 CueSheet::calculate_cddb_id() const
1061                 {
1062                         FLAC__ASSERT(is_valid());
1063                         return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
1064                 }
1065
1066
1067                 //
1068                 // Picture
1069                 //
1070
1071                 Picture::Picture():
1072                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
1073                 { }
1074
1075                 Picture::~Picture()
1076                 { }
1077
1078                 ::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
1079                 {
1080                         FLAC__ASSERT(is_valid());
1081                         return object_->data.picture.type;
1082                 }
1083
1084                 const char *Picture::get_mime_type() const
1085                 {
1086                         FLAC__ASSERT(is_valid());
1087                         return object_->data.picture.mime_type;
1088                 }
1089
1090                 const FLAC__byte *Picture::get_description() const
1091                 {
1092                         FLAC__ASSERT(is_valid());
1093                         return object_->data.picture.description;
1094                 }
1095
1096                 FLAC__uint32 Picture::get_width() const
1097                 {
1098                         FLAC__ASSERT(is_valid());
1099                         return object_->data.picture.width;
1100                 }
1101
1102                 FLAC__uint32 Picture::get_height() const
1103                 {
1104                         FLAC__ASSERT(is_valid());
1105                         return object_->data.picture.height;
1106                 }
1107
1108                 FLAC__uint32 Picture::get_depth() const
1109                 {
1110                         FLAC__ASSERT(is_valid());
1111                         return object_->data.picture.depth;
1112                 }
1113
1114                 FLAC__uint32 Picture::get_colors() const
1115                 {
1116                         FLAC__ASSERT(is_valid());
1117                         return object_->data.picture.colors;
1118                 }
1119
1120                 FLAC__uint32 Picture::get_data_length() const
1121                 {
1122                         FLAC__ASSERT(is_valid());
1123                         return object_->data.picture.data_length;
1124                 }
1125
1126                 const FLAC__byte *Picture::get_data() const
1127                 {
1128                         FLAC__ASSERT(is_valid());
1129                         return object_->data.picture.data;
1130                 }
1131
1132                 void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
1133                 {
1134                         FLAC__ASSERT(is_valid());
1135                         object_->data.picture.type = type;
1136                 }
1137
1138                 bool Picture::set_mime_type(const char *string)
1139                 {
1140                         FLAC__ASSERT(is_valid());
1141                         // We can safely const_cast since copy=true
1142                         return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true);
1143                 }
1144
1145                 bool Picture::set_description(const FLAC__byte *string)
1146                 {
1147                         FLAC__ASSERT(is_valid());
1148                         // We can safely const_cast since copy=true
1149                         return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true);
1150                 }
1151
1152                 void Picture::set_width(FLAC__uint32 value) const
1153                 {
1154                         FLAC__ASSERT(is_valid());
1155                         object_->data.picture.width = value;
1156                 }
1157
1158                 void Picture::set_height(FLAC__uint32 value) const
1159                 {
1160                         FLAC__ASSERT(is_valid());
1161                         object_->data.picture.height = value;
1162                 }
1163
1164                 void Picture::set_depth(FLAC__uint32 value) const
1165                 {
1166                         FLAC__ASSERT(is_valid());
1167                         object_->data.picture.depth = value;
1168                 }
1169
1170                 void Picture::set_colors(FLAC__uint32 value) const
1171                 {
1172                         FLAC__ASSERT(is_valid());
1173                         object_->data.picture.colors = value;
1174                 }
1175
1176                 bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
1177                 {
1178                         FLAC__ASSERT(is_valid());
1179                         // We can safely const_cast since copy=true
1180                         return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
1181                 }
1182
1183
1184                 //
1185                 // Unknown
1186                 //
1187
1188                 Unknown::Unknown():
1189                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
1190                 { }
1191
1192                 Unknown::~Unknown()
1193                 { }
1194
1195                 const FLAC__byte *Unknown::get_data() const
1196                 {
1197                         FLAC__ASSERT(is_valid());
1198                         return object_->data.application.data;
1199                 }
1200
1201                 bool Unknown::set_data(const FLAC__byte *data, unsigned length)
1202                 {
1203                         FLAC__ASSERT(is_valid());
1204                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
1205                 }
1206
1207                 bool Unknown::set_data(FLAC__byte *data, unsigned length, bool copy)
1208                 {
1209                         FLAC__ASSERT(is_valid());
1210                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
1211                 }
1212
1213
1214                 // ============================================================
1215                 //
1216                 //  Level 0
1217                 //
1218                 // ============================================================
1219
1220                 FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
1221                 {
1222                         FLAC__ASSERT(0 != filename);
1223
1224                         ::FLAC__StreamMetadata object;
1225
1226                         if(::FLAC__metadata_get_streaminfo(filename, &object)) {
1227                                 streaminfo = object;
1228                                 return true;
1229                         }
1230                         else
1231                                 return false;
1232                 }
1233
1234                 FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
1235                 {
1236                         FLAC__ASSERT(0 != filename);
1237
1238                         ::FLAC__StreamMetadata *object;
1239
1240                         tags = 0;
1241
1242                         if(::FLAC__metadata_get_tags(filename, &object)) {
1243                                 tags = new VorbisComment(object, /*copy=*/false);
1244                                 return true;
1245                         }
1246                         else
1247                                 return false;
1248                 }
1249
1250                 FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
1251                 {
1252                         FLAC__ASSERT(0 != filename);
1253
1254                         ::FLAC__StreamMetadata *object;
1255
1256                         if(::FLAC__metadata_get_tags(filename, &object)) {
1257                                 tags.assign(object, /*copy=*/false);
1258                                 return true;
1259                         }
1260                         else
1261                                 return false;
1262                 }
1263
1264                 FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
1265                 {
1266                         FLAC__ASSERT(0 != filename);
1267
1268                         ::FLAC__StreamMetadata *object;
1269
1270                         cuesheet = 0;
1271
1272                         if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1273                                 cuesheet = new CueSheet(object, /*copy=*/false);
1274                                 return true;
1275                         }
1276                         else
1277                                 return false;
1278                 }
1279
1280                 FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
1281                 {
1282                         FLAC__ASSERT(0 != filename);
1283
1284                         ::FLAC__StreamMetadata *object;
1285
1286                         if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1287                                 cuesheet.assign(object, /*copy=*/false);
1288                                 return true;
1289                         }
1290                         else
1291                                 return false;
1292                 }
1293
1294                 FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
1295                 {
1296                         FLAC__ASSERT(0 != filename);
1297
1298                         ::FLAC__StreamMetadata *object;
1299
1300                         picture = 0;
1301
1302                         if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1303                                 picture = new Picture(object, /*copy=*/false);
1304                                 return true;
1305                         }
1306                         else
1307                                 return false;
1308                 }
1309
1310                 FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
1311                 {
1312                         FLAC__ASSERT(0 != filename);
1313
1314                         ::FLAC__StreamMetadata *object;
1315
1316                         if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1317                                 picture.assign(object, /*copy=*/false);
1318                                 return true;
1319                         }
1320                         else
1321                                 return false;
1322                 }
1323
1324
1325                 // ============================================================
1326                 //
1327                 //  Level 1
1328                 //
1329                 // ============================================================
1330
1331                 SimpleIterator::SimpleIterator():
1332                 iterator_(::FLAC__metadata_simple_iterator_new())
1333                 { }
1334
1335                 SimpleIterator::~SimpleIterator()
1336                 {
1337                         clear();
1338                 }
1339
1340                 void SimpleIterator::clear()
1341                 {
1342                         if(0 != iterator_)
1343                                 FLAC__metadata_simple_iterator_delete(iterator_);
1344                         iterator_ = 0;
1345                 }
1346
1347                 bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
1348                 {
1349                         FLAC__ASSERT(0 != filename);
1350                         FLAC__ASSERT(is_valid());
1351                         return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
1352                 }
1353
1354                 bool SimpleIterator::is_valid() const
1355                 {
1356                         return 0 != iterator_;
1357                 }
1358
1359                 SimpleIterator::Status SimpleIterator::status()
1360                 {
1361                         FLAC__ASSERT(is_valid());
1362                         return Status(::FLAC__metadata_simple_iterator_status(iterator_));
1363                 }
1364
1365                 bool SimpleIterator::is_writable() const
1366                 {
1367                         FLAC__ASSERT(is_valid());
1368                         return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
1369                 }
1370
1371                 bool SimpleIterator::next()
1372                 {
1373                         FLAC__ASSERT(is_valid());
1374                         return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
1375                 }
1376
1377                 bool SimpleIterator::prev()
1378                 {
1379                         FLAC__ASSERT(is_valid());
1380                         return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
1381                 }
1382
1383                 //@@@@ add to tests
1384                 bool SimpleIterator::is_last() const
1385                 {
1386                         FLAC__ASSERT(is_valid());
1387                         return (bool)::FLAC__metadata_simple_iterator_is_last(iterator_);
1388                 }
1389
1390                 //@@@@ add to tests
1391                 off_t SimpleIterator::get_block_offset() const
1392                 {
1393                         FLAC__ASSERT(is_valid());
1394                         return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
1395                 }
1396
1397                 ::FLAC__MetadataType SimpleIterator::get_block_type() const
1398                 {
1399                         FLAC__ASSERT(is_valid());
1400                         return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
1401                 }
1402
1403                 //@@@@ add to tests
1404                 unsigned SimpleIterator::get_block_length() const
1405                 {
1406                         FLAC__ASSERT(is_valid());
1407                         return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
1408                 }
1409
1410                 //@@@@ add to tests
1411                 bool SimpleIterator::get_application_id(FLAC__byte *id)
1412                 {
1413                         FLAC__ASSERT(is_valid());
1414                         return (bool)::FLAC__metadata_simple_iterator_get_application_id(iterator_, id);
1415                 }
1416
1417                 Prototype *SimpleIterator::get_block()
1418                 {
1419                         FLAC__ASSERT(is_valid());
1420                         return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
1421                 }
1422
1423                 bool SimpleIterator::set_block(Prototype *block, bool use_padding)
1424                 {
1425                         FLAC__ASSERT(0 != block);
1426                         FLAC__ASSERT(is_valid());
1427                         return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
1428                 }
1429
1430                 bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
1431                 {
1432                         FLAC__ASSERT(0 != block);
1433                         FLAC__ASSERT(is_valid());
1434                         return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
1435                 }
1436
1437                 bool SimpleIterator::delete_block(bool use_padding)
1438                 {
1439                         FLAC__ASSERT(is_valid());
1440                         return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
1441                 }
1442
1443
1444                 // ============================================================
1445                 //
1446                 //  Level 2
1447                 //
1448                 // ============================================================
1449
1450                 Chain::Chain():
1451                 chain_(::FLAC__metadata_chain_new())
1452                 { }
1453
1454                 Chain::~Chain()
1455                 {
1456                         clear();
1457                 }
1458
1459                 void Chain::clear()
1460                 {
1461                         if(0 != chain_)
1462                                 FLAC__metadata_chain_delete(chain_);
1463                         chain_ = 0;
1464                 }
1465
1466                 bool Chain::is_valid() const
1467                 {
1468                         return 0 != chain_;
1469                 }
1470
1471                 Chain::Status Chain::status()
1472                 {
1473                         FLAC__ASSERT(is_valid());
1474                         return Status(::FLAC__metadata_chain_status(chain_));
1475                 }
1476
1477                 bool Chain::read(const char *filename, bool is_ogg)
1478                 {
1479                         FLAC__ASSERT(0 != filename);
1480                         FLAC__ASSERT(is_valid());
1481                         return is_ogg?
1482                                 (bool)::FLAC__metadata_chain_read_ogg(chain_, filename) :
1483                                 (bool)::FLAC__metadata_chain_read(chain_, filename)
1484                         ;
1485                 }
1486
1487                 bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg)
1488                 {
1489                         FLAC__ASSERT(is_valid());
1490                         return is_ogg?
1491                                 (bool)::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks) :
1492                                 (bool)::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks)
1493                         ;
1494                 }
1495
1496                 bool Chain::check_if_tempfile_needed(bool use_padding)
1497                 {
1498                         FLAC__ASSERT(is_valid());
1499                         return (bool)::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
1500                 }
1501
1502                 bool Chain::write(bool use_padding, bool preserve_file_stats)
1503                 {
1504                         FLAC__ASSERT(is_valid());
1505                         return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
1506                 }
1507
1508                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
1509                 {
1510                         FLAC__ASSERT(is_valid());
1511                         return (bool)::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
1512                 }
1513
1514                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
1515                 {
1516                         FLAC__ASSERT(is_valid());
1517                         return (bool)::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
1518                 }
1519
1520                 void Chain::merge_padding()
1521                 {
1522                         FLAC__ASSERT(is_valid());
1523                         ::FLAC__metadata_chain_merge_padding(chain_);
1524                 }
1525
1526                 void Chain::sort_padding()
1527                 {
1528                         FLAC__ASSERT(is_valid());
1529                         ::FLAC__metadata_chain_sort_padding(chain_);
1530                 }
1531
1532
1533                 Iterator::Iterator():
1534                 iterator_(::FLAC__metadata_iterator_new())
1535                 { }
1536
1537                 Iterator::~Iterator()
1538                 {
1539                         clear();
1540                 }
1541
1542                 void Iterator::clear()
1543                 {
1544                         if(0 != iterator_)
1545                                 FLAC__metadata_iterator_delete(iterator_);
1546                         iterator_ = 0;
1547                 }
1548
1549                 bool Iterator::is_valid() const
1550                 {
1551                         return 0 != iterator_;
1552                 }
1553
1554                 void Iterator::init(Chain &chain)
1555                 {
1556                         FLAC__ASSERT(is_valid());
1557                         FLAC__ASSERT(chain.is_valid());
1558                         ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
1559                 }
1560
1561                 bool Iterator::next()
1562                 {
1563                         FLAC__ASSERT(is_valid());
1564                         return (bool)::FLAC__metadata_iterator_next(iterator_);
1565                 }
1566
1567                 bool Iterator::prev()
1568                 {
1569                         FLAC__ASSERT(is_valid());
1570                         return (bool)::FLAC__metadata_iterator_prev(iterator_);
1571                 }
1572
1573                 ::FLAC__MetadataType Iterator::get_block_type() const
1574                 {
1575                         FLAC__ASSERT(is_valid());
1576                         return ::FLAC__metadata_iterator_get_block_type(iterator_);
1577                 }
1578
1579                 Prototype *Iterator::get_block()
1580                 {
1581                         FLAC__ASSERT(is_valid());
1582                         Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
1583                         if(0 != block)
1584                                 block->set_reference(true);
1585                         return block;
1586                 }
1587
1588                 bool Iterator::set_block(Prototype *block)
1589                 {
1590                         FLAC__ASSERT(0 != block);
1591                         FLAC__ASSERT(is_valid());
1592                         bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
1593                         if(ret) {
1594                                 block->set_reference(true);
1595                                 delete block;
1596                         }
1597                         return ret;
1598                 }
1599
1600                 bool Iterator::delete_block(bool replace_with_padding)
1601                 {
1602                         FLAC__ASSERT(is_valid());
1603                         return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
1604                 }
1605
1606                 bool Iterator::insert_block_before(Prototype *block)
1607                 {
1608                         FLAC__ASSERT(0 != block);
1609                         FLAC__ASSERT(is_valid());
1610                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
1611                         if(ret) {
1612                                 block->set_reference(true);
1613                                 delete block;
1614                         }
1615                         return ret;
1616                 }
1617
1618                 bool Iterator::insert_block_after(Prototype *block)
1619                 {
1620                         FLAC__ASSERT(0 != block);
1621                         FLAC__ASSERT(is_valid());
1622                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1623                         if(ret) {
1624                                 block->set_reference(true);
1625                                 delete block;
1626                         }
1627                         return ret;
1628                 }
1629
1630         }
1631 }