extra checking on memory allocation sizes to prevent a class of overflow attacks
[platform/upstream/flac.git] / src / libFLAC++ / metadata.cpp
1 /* libFLAC++ - Free Lossless Audio Codec library
2  * Copyright (C) 2002,2003,2004,2005,2006,2007  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                 void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
442                 {
443                         FLAC__ASSERT(is_valid());
444                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
445                         ::FLAC__metadata_object_seektable_set_point(object_, index, point);
446                 }
447
448                 bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
449                 {
450                         FLAC__ASSERT(is_valid());
451                         FLAC__ASSERT(index <= object_->data.seek_table.num_points);
452                         return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
453                 }
454
455                 bool SeekTable::delete_point(unsigned index)
456                 {
457                         FLAC__ASSERT(is_valid());
458                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
459                         return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
460                 }
461
462                 bool SeekTable::is_legal() const
463                 {
464                         FLAC__ASSERT(is_valid());
465                         return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
466                 }
467
468
469                 //
470                 // VorbisComment::Entry
471                 //
472
473                 VorbisComment::Entry::Entry()
474                 {
475                         zero();
476                 }
477
478                 VorbisComment::Entry::Entry(const char *field, unsigned field_length)
479                 {
480                         zero();
481                         construct(field, field_length);
482                 }
483
484                 VorbisComment::Entry::Entry(const char *field)
485                 {
486                         zero();
487                         construct(field);
488                 }
489
490                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
491                 {
492                         zero();
493                         construct(field_name, field_value, field_value_length);
494                 }
495
496                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value)
497                 {
498                         zero();
499                         construct(field_name, field_value);
500                 }
501
502                 VorbisComment::Entry::Entry(const Entry &entry)
503                 {
504                         FLAC__ASSERT(entry.is_valid());
505                         zero();
506                         construct((const char *)entry.entry_.entry, entry.entry_.length);
507                 }
508
509                 VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
510                 {
511                         FLAC__ASSERT(entry.is_valid());
512                         clear();
513                         construct((const char *)entry.entry_.entry, entry.entry_.length);
514                         return *this;
515                 }
516
517                 VorbisComment::Entry::~Entry()
518                 {
519                         clear();
520                 }
521
522                 bool VorbisComment::Entry::is_valid() const
523                 {
524                         return is_valid_;
525                 }
526
527                 unsigned VorbisComment::Entry::get_field_length() const
528                 {
529                         FLAC__ASSERT(is_valid());
530                         return entry_.length;
531                 }
532
533                 unsigned VorbisComment::Entry::get_field_name_length() const
534                 {
535                         FLAC__ASSERT(is_valid());
536                         return field_name_length_;
537                 }
538
539                 unsigned VorbisComment::Entry::get_field_value_length() const
540                 {
541                         FLAC__ASSERT(is_valid());
542                         return field_value_length_;
543                 }
544
545                 ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
546                 {
547                         FLAC__ASSERT(is_valid());
548                         return entry_;
549                 }
550
551                 const char *VorbisComment::Entry::get_field() const
552                 {
553                         FLAC__ASSERT(is_valid());
554                         return (const char *)entry_.entry;
555                 }
556
557                 const char *VorbisComment::Entry::get_field_name() const
558                 {
559                         FLAC__ASSERT(is_valid());
560                         return field_name_;
561                 }
562
563                 const char *VorbisComment::Entry::get_field_value() const
564                 {
565                         FLAC__ASSERT(is_valid());
566                         return field_value_;
567                 }
568
569                 bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
570                 {
571                         FLAC__ASSERT(is_valid());
572                         FLAC__ASSERT(0 != field);
573
574                         if(!::FLAC__format_vorbiscomment_entry_is_legal((const ::FLAC__byte*)field, field_length))
575                                 return is_valid_ = false;
576
577                         clear_entry();
578
579                         if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_2op_(field_length, /*+*/1))) {
580                                 is_valid_ = false;
581                         }
582                         else {
583                                 entry_.length = field_length;
584                                 memcpy(entry_.entry, field, field_length);
585                                 entry_.entry[field_length] = '\0';
586                                 (void) parse_field();
587                         }
588
589                         return is_valid_;
590                 }
591
592                 bool VorbisComment::Entry::set_field(const char *field)
593                 {
594                         return set_field(field, strlen(field));
595                 }
596
597                 bool VorbisComment::Entry::set_field_name(const char *field_name)
598                 {
599                         FLAC__ASSERT(is_valid());
600                         FLAC__ASSERT(0 != field_name);
601
602                         if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
603                                 return is_valid_ = false;
604
605                         clear_field_name();
606
607                         if(0 == (field_name_ = strdup(field_name))) {
608                                 is_valid_ = false;
609                         }
610                         else {
611                                 field_name_length_ = strlen(field_name_);
612                                 compose_field();
613                         }
614
615                         return is_valid_;
616                 }
617
618                 bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
619                 {
620                         FLAC__ASSERT(is_valid());
621                         FLAC__ASSERT(0 != field_value);
622
623                         if(!::FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte*)field_value, field_value_length))
624                                 return is_valid_ = false;
625
626                         clear_field_value();
627
628                         if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length, /*+*/1))) {
629                                 is_valid_ = false;
630                         }
631                         else {
632                                 field_value_length_ = field_value_length;
633                                 memcpy(field_value_, field_value, field_value_length);
634                                 field_value_[field_value_length] = '\0';
635                                 compose_field();
636                         }
637
638                         return is_valid_;
639                 }
640
641                 bool VorbisComment::Entry::set_field_value(const char *field_value)
642                 {
643                         return set_field_value(field_value, strlen(field_value));
644                 }
645
646                 void VorbisComment::Entry::zero()
647                 {
648                         is_valid_ = true;
649                         entry_.length = 0;
650                         entry_.entry = 0;
651                         field_name_ = 0;
652                         field_name_length_ = 0;
653                         field_value_ = 0;
654                         field_value_length_ = 0;
655                 }
656
657                 void VorbisComment::Entry::clear()
658                 {
659                         clear_entry();
660                         clear_field_name();
661                         clear_field_value();
662                         is_valid_ = true;
663                 }
664
665                 void VorbisComment::Entry::clear_entry()
666                 {
667                         if(0 != entry_.entry) {
668                                 free(entry_.entry);
669                                 entry_.entry = 0;
670                                 entry_.length = 0;
671                         }
672                 }
673
674                 void VorbisComment::Entry::clear_field_name()
675                 {
676                         if(0 != field_name_) {
677                                 free(field_name_);
678                                 field_name_ = 0;
679                                 field_name_length_ = 0;
680                         }
681                 }
682
683                 void VorbisComment::Entry::clear_field_value()
684                 {
685                         if(0 != field_value_) {
686                                 free(field_value_);
687                                 field_value_ = 0;
688                                 field_value_length_ = 0;
689                         }
690                 }
691
692                 void VorbisComment::Entry::construct(const char *field, unsigned field_length)
693                 {
694                         if(set_field(field, field_length))
695                                 parse_field();
696                 }
697
698                 void VorbisComment::Entry::construct(const char *field)
699                 {
700                         construct(field, strlen(field));
701                 }
702
703                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
704                 {
705                         if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
706                                 compose_field();
707                 }
708
709                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
710                 {
711                         construct(field_name, field_value, strlen(field_value));
712                 }
713
714                 void VorbisComment::Entry::compose_field()
715                 {
716                         clear_entry();
717
718                         if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1))) {
719                                 is_valid_ = false;
720                         }
721                         else {
722                                 memcpy(entry_.entry, field_name_, field_name_length_);
723                                 entry_.length += field_name_length_;
724                                 memcpy(entry_.entry + entry_.length, "=", 1);
725                                 entry_.length += 1;
726                                 memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
727                                 entry_.length += field_value_length_;
728                                 entry_.entry[entry_.length] = '\0';
729                                 is_valid_ = true;
730                         }
731                 }
732
733                 void VorbisComment::Entry::parse_field()
734                 {
735                         clear_field_name();
736                         clear_field_value();
737
738                         const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
739
740                         if(0 == p)
741                                 p = (const char *)entry_.entry + entry_.length;
742
743                         field_name_length_ = (unsigned)(p - (const char *)entry_.entry);
744                         if(0 == (field_name_ = (char *)safe_malloc_add_2op_(field_name_length_, /*+*/1))) { // +1 for the trailing \0
745                                 is_valid_ = false;
746                                 return;
747                         }
748                         memcpy(field_name_, entry_.entry, field_name_length_);
749                         field_name_[field_name_length_] = '\0';
750
751                         if(entry_.length - field_name_length_ == 0) {
752                                 field_value_length_ = 0;
753                                 if(0 == (field_value_ = (char *)safe_malloc_(0))) {
754                                         is_valid_ = false;
755                                         return;
756                                 }
757                         }
758                         else {
759                                 field_value_length_ = entry_.length - field_name_length_ - 1;
760                                 if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length_, /*+*/1))) { // +1 for the trailing \0
761                                         is_valid_ = false;
762                                         return;
763                                 }
764                                 memcpy(field_value_, ++p, field_value_length_);
765                                 field_value_[field_value_length_] = '\0';
766                         }
767
768                         is_valid_ = true;
769                 }
770
771
772                 //
773                 // VorbisComment
774                 //
775
776                 VorbisComment::VorbisComment():
777                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
778                 { }
779
780                 VorbisComment::~VorbisComment()
781                 { }
782
783                 unsigned VorbisComment::get_num_comments() const
784                 {
785                         FLAC__ASSERT(is_valid());
786                         return object_->data.vorbis_comment.num_comments;
787                 }
788
789                 const FLAC__byte *VorbisComment::get_vendor_string() const
790                 {
791                         FLAC__ASSERT(is_valid());
792                         return object_->data.vorbis_comment.vendor_string.entry;
793                 }
794
795                 VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
796                 {
797                         FLAC__ASSERT(is_valid());
798                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
799                         return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
800                 }
801
802                 bool VorbisComment::set_vendor_string(const FLAC__byte *string)
803                 {
804                         FLAC__ASSERT(is_valid());
805                         // vendor_string is a special kind of entry
806                         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:
807                         return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
808                 }
809
810                 bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
811                 {
812                         FLAC__ASSERT(is_valid());
813                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
814                         return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
815                 }
816
817                 bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
818                 {
819                         FLAC__ASSERT(is_valid());
820                         FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
821                         return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
822                 }
823
824                 bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
825                 {
826                         FLAC__ASSERT(is_valid());
827                         return (bool)::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true);
828                 }
829
830                 bool VorbisComment::delete_comment(unsigned index)
831                 {
832                         FLAC__ASSERT(is_valid());
833                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
834                         return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
835                 }
836
837
838                 //
839                 // CueSheet::Track
840                 //
841
842                 CueSheet::Track::Track():
843                 object_(::FLAC__metadata_object_cuesheet_track_new())
844                 { }
845
846                 CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track):
847                 object_(::FLAC__metadata_object_cuesheet_track_clone(track))
848                 { }
849
850                 CueSheet::Track::Track(const Track &track):
851                 object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_))
852                 { }
853
854                 CueSheet::Track &CueSheet::Track::operator=(const Track &track)
855                 {
856                         if(0 != object_)
857                                 ::FLAC__metadata_object_cuesheet_track_delete(object_);
858                         object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_);
859                         return *this;
860                 }
861
862                 CueSheet::Track::~Track()
863                 {
864                         if(0 != object_)
865                                 ::FLAC__metadata_object_cuesheet_track_delete(object_);
866                 }
867
868                 bool CueSheet::Track::is_valid() const
869                 {
870                         return(0 != object_);
871                 }
872
873                 ::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(unsigned i) const
874                 {
875                         FLAC__ASSERT(is_valid());
876                         FLAC__ASSERT(i < object_->num_indices);
877                         return object_->indices[i];
878                 }
879
880                 void CueSheet::Track::set_isrc(const char value[12])
881                 {
882                         FLAC__ASSERT(is_valid());
883                         FLAC__ASSERT(0 != value);
884                         memcpy(object_->isrc, value, 12);
885                         object_->isrc[12] = '\0';
886                 }
887
888                 void CueSheet::Track::set_type(unsigned value)
889                 {
890                         FLAC__ASSERT(is_valid());
891                         FLAC__ASSERT(value <= 1);
892                         object_->type = value;
893                 }
894
895                 void CueSheet::Track::set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index)
896                 {
897                         FLAC__ASSERT(is_valid());
898                         FLAC__ASSERT(i < object_->num_indices);
899                         object_->indices[i] = index;
900                 }
901
902
903                 //
904                 // CueSheet
905                 //
906
907                 CueSheet::CueSheet():
908                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false)
909                 { }
910
911                 CueSheet::~CueSheet()
912                 { }
913
914                 const char *CueSheet::get_media_catalog_number() const
915                 {
916                         FLAC__ASSERT(is_valid());
917                         return object_->data.cue_sheet.media_catalog_number;
918                 }
919
920                 FLAC__uint64 CueSheet::get_lead_in() const
921                 {
922                         FLAC__ASSERT(is_valid());
923                         return object_->data.cue_sheet.lead_in;
924                 }
925
926                 bool CueSheet::get_is_cd() const
927                 {
928                         FLAC__ASSERT(is_valid());
929                         return object_->data.cue_sheet.is_cd? true : false;
930                 }
931
932                 unsigned CueSheet::get_num_tracks() const
933                 {
934                         FLAC__ASSERT(is_valid());
935                         return object_->data.cue_sheet.num_tracks;
936                 }
937
938                 CueSheet::Track CueSheet::get_track(unsigned i) const
939                 {
940                         FLAC__ASSERT(is_valid());
941                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
942                         return Track(object_->data.cue_sheet.tracks + i);
943                 }
944
945                 void CueSheet::set_media_catalog_number(const char value[128])
946                 {
947                         FLAC__ASSERT(is_valid());
948                         FLAC__ASSERT(0 != value);
949                         memcpy(object_->data.cue_sheet.media_catalog_number, value, 128);
950                         object_->data.cue_sheet.media_catalog_number[128] = '\0';
951                 }
952
953                 void CueSheet::set_lead_in(FLAC__uint64 value)
954                 {
955                         FLAC__ASSERT(is_valid());
956                         object_->data.cue_sheet.lead_in = value;
957                 }
958
959                 void CueSheet::set_is_cd(bool value)
960                 {
961                         FLAC__ASSERT(is_valid());
962                         object_->data.cue_sheet.is_cd = value;
963                 }
964
965                 void CueSheet::set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
966                 {
967                         FLAC__ASSERT(is_valid());
968                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
969                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
970                         object_->data.cue_sheet.tracks[track_num].indices[index_num] = index;
971                 }
972
973                 bool CueSheet::insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
974                 {
975                         FLAC__ASSERT(is_valid());
976                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
977                         FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
978                         return (bool)::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, index);
979                 }
980
981                 bool CueSheet::delete_index(unsigned track_num, unsigned index_num)
982                 {
983                         FLAC__ASSERT(is_valid());
984                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
985                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
986                         return (bool)::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num);
987                 }
988
989                 bool CueSheet::set_track(unsigned i, const CueSheet::Track &track)
990                 {
991                         FLAC__ASSERT(is_valid());
992                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
993                         // We can safely const_cast since copy=true
994                         return (bool)::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
995                 }
996
997                 bool CueSheet::insert_track(unsigned i, const CueSheet::Track &track)
998                 {
999                         FLAC__ASSERT(is_valid());
1000                         FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
1001                         // We can safely const_cast since copy=true
1002                         return (bool)::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
1003                 }
1004
1005                 bool CueSheet::delete_track(unsigned i)
1006                 {
1007                         FLAC__ASSERT(is_valid());
1008                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1009                         return (bool)::FLAC__metadata_object_cuesheet_delete_track(object_, i);
1010                 }
1011
1012                 bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
1013                 {
1014                         FLAC__ASSERT(is_valid());
1015                         return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
1016                 }
1017
1018                 FLAC__uint32 CueSheet::calculate_cddb_id() const
1019                 {
1020                         FLAC__ASSERT(is_valid());
1021                         return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
1022                 }
1023
1024
1025                 //
1026                 // Picture
1027                 //
1028
1029                 Picture::Picture():
1030                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
1031                 { }
1032
1033                 Picture::~Picture()
1034                 { }
1035
1036                 ::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
1037                 {
1038                         FLAC__ASSERT(is_valid());
1039                         return object_->data.picture.type;
1040                 }
1041
1042                 const char *Picture::get_mime_type() const
1043                 {
1044                         FLAC__ASSERT(is_valid());
1045                         return object_->data.picture.mime_type;
1046                 }
1047
1048                 const FLAC__byte *Picture::get_description() const
1049                 {
1050                         FLAC__ASSERT(is_valid());
1051                         return object_->data.picture.description;
1052                 }
1053
1054                 FLAC__uint32 Picture::get_width() const
1055                 {
1056                         FLAC__ASSERT(is_valid());
1057                         return object_->data.picture.width;
1058                 }
1059
1060                 FLAC__uint32 Picture::get_height() const
1061                 {
1062                         FLAC__ASSERT(is_valid());
1063                         return object_->data.picture.height;
1064                 }
1065
1066                 FLAC__uint32 Picture::get_depth() const
1067                 {
1068                         FLAC__ASSERT(is_valid());
1069                         return object_->data.picture.depth;
1070                 }
1071
1072                 FLAC__uint32 Picture::get_colors() const
1073                 {
1074                         FLAC__ASSERT(is_valid());
1075                         return object_->data.picture.colors;
1076                 }
1077
1078                 FLAC__uint32 Picture::get_data_length() const
1079                 {
1080                         FLAC__ASSERT(is_valid());
1081                         return object_->data.picture.data_length;
1082                 }
1083
1084                 const FLAC__byte *Picture::get_data() const
1085                 {
1086                         FLAC__ASSERT(is_valid());
1087                         return object_->data.picture.data;
1088                 }
1089
1090                 void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
1091                 {
1092                         FLAC__ASSERT(is_valid());
1093                         object_->data.picture.type = type;
1094                 }
1095
1096                 bool Picture::set_mime_type(const char *string)
1097                 {
1098                         FLAC__ASSERT(is_valid());
1099                         // We can safely const_cast since copy=true
1100                         return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true);
1101                 }
1102
1103                 bool Picture::set_description(const FLAC__byte *string)
1104                 {
1105                         FLAC__ASSERT(is_valid());
1106                         // We can safely const_cast since copy=true
1107                         return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true);
1108                 }
1109
1110                 void Picture::set_width(FLAC__uint32 value) const
1111                 {
1112                         FLAC__ASSERT(is_valid());
1113                         object_->data.picture.width = value;
1114                 }
1115
1116                 void Picture::set_height(FLAC__uint32 value) const
1117                 {
1118                         FLAC__ASSERT(is_valid());
1119                         object_->data.picture.height = value;
1120                 }
1121
1122                 void Picture::set_depth(FLAC__uint32 value) const
1123                 {
1124                         FLAC__ASSERT(is_valid());
1125                         object_->data.picture.depth = value;
1126                 }
1127
1128                 void Picture::set_colors(FLAC__uint32 value) const
1129                 {
1130                         FLAC__ASSERT(is_valid());
1131                         object_->data.picture.colors = value;
1132                 }
1133
1134                 bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
1135                 {
1136                         FLAC__ASSERT(is_valid());
1137                         // We can safely const_cast since copy=true
1138                         return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
1139                 }
1140
1141
1142                 //
1143                 // Unknown
1144                 //
1145
1146                 Unknown::Unknown():
1147                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
1148                 { }
1149
1150                 Unknown::~Unknown()
1151                 { }
1152
1153                 const FLAC__byte *Unknown::get_data() const
1154                 {
1155                         FLAC__ASSERT(is_valid());
1156                         return object_->data.application.data;
1157                 }
1158
1159                 bool Unknown::set_data(const FLAC__byte *data, unsigned length)
1160                 {
1161                         FLAC__ASSERT(is_valid());
1162                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
1163                 }
1164
1165                 bool Unknown::set_data(FLAC__byte *data, unsigned length, bool copy)
1166                 {
1167                         FLAC__ASSERT(is_valid());
1168                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
1169                 }
1170
1171
1172                 // ============================================================
1173                 //
1174                 //  Level 0
1175                 //
1176                 // ============================================================
1177
1178                 FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
1179                 {
1180                         FLAC__ASSERT(0 != filename);
1181
1182                         ::FLAC__StreamMetadata object;
1183
1184                         if(::FLAC__metadata_get_streaminfo(filename, &object)) {
1185                                 streaminfo = object;
1186                                 return true;
1187                         }
1188                         else
1189                                 return false;
1190                 }
1191
1192                 FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
1193                 {
1194                         FLAC__ASSERT(0 != filename);
1195
1196                         ::FLAC__StreamMetadata *object;
1197
1198                         tags = 0;
1199
1200                         if(::FLAC__metadata_get_tags(filename, &object)) {
1201                                 tags = new VorbisComment(object, /*copy=*/false);
1202                                 return true;
1203                         }
1204                         else
1205                                 return false;
1206                 }
1207
1208                 FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
1209                 {
1210                         FLAC__ASSERT(0 != filename);
1211
1212                         ::FLAC__StreamMetadata *object;
1213
1214                         if(::FLAC__metadata_get_tags(filename, &object)) {
1215                                 tags.assign(object, /*copy=*/false);
1216                                 return true;
1217                         }
1218                         else
1219                                 return false;
1220                 }
1221
1222                 FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
1223                 {
1224                         FLAC__ASSERT(0 != filename);
1225
1226                         ::FLAC__StreamMetadata *object;
1227
1228                         cuesheet = 0;
1229
1230                         if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1231                                 cuesheet = new CueSheet(object, /*copy=*/false);
1232                                 return true;
1233                         }
1234                         else
1235                                 return false;
1236                 }
1237
1238                 FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
1239                 {
1240                         FLAC__ASSERT(0 != filename);
1241
1242                         ::FLAC__StreamMetadata *object;
1243
1244                         if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1245                                 cuesheet.assign(object, /*copy=*/false);
1246                                 return true;
1247                         }
1248                         else
1249                                 return false;
1250                 }
1251
1252                 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)
1253                 {
1254                         FLAC__ASSERT(0 != filename);
1255
1256                         ::FLAC__StreamMetadata *object;
1257
1258                         picture = 0;
1259
1260                         if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1261                                 picture = new Picture(object, /*copy=*/false);
1262                                 return true;
1263                         }
1264                         else
1265                                 return false;
1266                 }
1267
1268                 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)
1269                 {
1270                         FLAC__ASSERT(0 != filename);
1271
1272                         ::FLAC__StreamMetadata *object;
1273
1274                         if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1275                                 picture.assign(object, /*copy=*/false);
1276                                 return true;
1277                         }
1278                         else
1279                                 return false;
1280                 }
1281
1282
1283                 // ============================================================
1284                 //
1285                 //  Level 1
1286                 //
1287                 // ============================================================
1288
1289                 SimpleIterator::SimpleIterator():
1290                 iterator_(::FLAC__metadata_simple_iterator_new())
1291                 { }
1292
1293                 SimpleIterator::~SimpleIterator()
1294                 {
1295                         clear();
1296                 }
1297
1298                 void SimpleIterator::clear()
1299                 {
1300                         if(0 != iterator_)
1301                                 FLAC__metadata_simple_iterator_delete(iterator_);
1302                         iterator_ = 0;
1303                 }
1304
1305                 bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
1306                 {
1307                         FLAC__ASSERT(0 != filename);
1308                         FLAC__ASSERT(is_valid());
1309                         return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
1310                 }
1311
1312                 bool SimpleIterator::is_valid() const
1313                 {
1314                         return 0 != iterator_;
1315                 }
1316
1317                 SimpleIterator::Status SimpleIterator::status()
1318                 {
1319                         FLAC__ASSERT(is_valid());
1320                         return Status(::FLAC__metadata_simple_iterator_status(iterator_));
1321                 }
1322
1323                 bool SimpleIterator::is_writable() const
1324                 {
1325                         FLAC__ASSERT(is_valid());
1326                         return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
1327                 }
1328
1329                 bool SimpleIterator::next()
1330                 {
1331                         FLAC__ASSERT(is_valid());
1332                         return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
1333                 }
1334
1335                 bool SimpleIterator::prev()
1336                 {
1337                         FLAC__ASSERT(is_valid());
1338                         return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
1339                 }
1340
1341                 //@@@@ add to tests
1342                 bool SimpleIterator::is_last() const
1343                 {
1344                         FLAC__ASSERT(is_valid());
1345                         return (bool)::FLAC__metadata_simple_iterator_is_last(iterator_);
1346                 }
1347
1348                 //@@@@ add to tests
1349                 off_t SimpleIterator::get_block_offset() const
1350                 {
1351                         FLAC__ASSERT(is_valid());
1352                         return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
1353                 }
1354
1355                 ::FLAC__MetadataType SimpleIterator::get_block_type() const
1356                 {
1357                         FLAC__ASSERT(is_valid());
1358                         return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
1359                 }
1360
1361                 //@@@@ add to tests
1362                 unsigned SimpleIterator::get_block_length() const
1363                 {
1364                         FLAC__ASSERT(is_valid());
1365                         return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
1366                 }
1367
1368                 //@@@@ add to tests
1369                 bool SimpleIterator::get_application_id(FLAC__byte *id)
1370                 {
1371                         FLAC__ASSERT(is_valid());
1372                         return (bool)::FLAC__metadata_simple_iterator_get_application_id(iterator_, id);
1373                 }
1374
1375                 Prototype *SimpleIterator::get_block()
1376                 {
1377                         FLAC__ASSERT(is_valid());
1378                         return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
1379                 }
1380
1381                 bool SimpleIterator::set_block(Prototype *block, bool use_padding)
1382                 {
1383                         FLAC__ASSERT(0 != block);
1384                         FLAC__ASSERT(is_valid());
1385                         return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
1386                 }
1387
1388                 bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
1389                 {
1390                         FLAC__ASSERT(0 != block);
1391                         FLAC__ASSERT(is_valid());
1392                         return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
1393                 }
1394
1395                 bool SimpleIterator::delete_block(bool use_padding)
1396                 {
1397                         FLAC__ASSERT(is_valid());
1398                         return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
1399                 }
1400
1401
1402                 // ============================================================
1403                 //
1404                 //  Level 2
1405                 //
1406                 // ============================================================
1407
1408                 Chain::Chain():
1409                 chain_(::FLAC__metadata_chain_new())
1410                 { }
1411
1412                 Chain::~Chain()
1413                 {
1414                         clear();
1415                 }
1416
1417                 void Chain::clear()
1418                 {
1419                         if(0 != chain_)
1420                                 FLAC__metadata_chain_delete(chain_);
1421                         chain_ = 0;
1422                 }
1423
1424                 bool Chain::is_valid() const
1425                 {
1426                         return 0 != chain_;
1427                 }
1428
1429                 Chain::Status Chain::status()
1430                 {
1431                         FLAC__ASSERT(is_valid());
1432                         return Status(::FLAC__metadata_chain_status(chain_));
1433                 }
1434
1435                 bool Chain::read(const char *filename, bool is_ogg)
1436                 {
1437                         FLAC__ASSERT(0 != filename);
1438                         FLAC__ASSERT(is_valid());
1439                         return is_ogg?
1440                                 (bool)::FLAC__metadata_chain_read_ogg(chain_, filename) :
1441                                 (bool)::FLAC__metadata_chain_read(chain_, filename)
1442                         ;
1443                 }
1444
1445                 bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg)
1446                 {
1447                         FLAC__ASSERT(is_valid());
1448                         return is_ogg?
1449                                 (bool)::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks) :
1450                                 (bool)::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks)
1451                         ;
1452                 }
1453
1454                 bool Chain::check_if_tempfile_needed(bool use_padding)
1455                 {
1456                         FLAC__ASSERT(is_valid());
1457                         return (bool)::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
1458                 }
1459
1460                 bool Chain::write(bool use_padding, bool preserve_file_stats)
1461                 {
1462                         FLAC__ASSERT(is_valid());
1463                         return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
1464                 }
1465
1466                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
1467                 {
1468                         FLAC__ASSERT(is_valid());
1469                         return (bool)::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
1470                 }
1471
1472                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
1473                 {
1474                         FLAC__ASSERT(is_valid());
1475                         return (bool)::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
1476                 }
1477
1478                 void Chain::merge_padding()
1479                 {
1480                         FLAC__ASSERT(is_valid());
1481                         ::FLAC__metadata_chain_merge_padding(chain_);
1482                 }
1483
1484                 void Chain::sort_padding()
1485                 {
1486                         FLAC__ASSERT(is_valid());
1487                         ::FLAC__metadata_chain_sort_padding(chain_);
1488                 }
1489
1490
1491                 Iterator::Iterator():
1492                 iterator_(::FLAC__metadata_iterator_new())
1493                 { }
1494
1495                 Iterator::~Iterator()
1496                 {
1497                         clear();
1498                 }
1499
1500                 void Iterator::clear()
1501                 {
1502                         if(0 != iterator_)
1503                                 FLAC__metadata_iterator_delete(iterator_);
1504                         iterator_ = 0;
1505                 }
1506
1507                 bool Iterator::is_valid() const
1508                 {
1509                         return 0 != iterator_;
1510                 }
1511
1512                 void Iterator::init(Chain &chain)
1513                 {
1514                         FLAC__ASSERT(is_valid());
1515                         FLAC__ASSERT(chain.is_valid());
1516                         ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
1517                 }
1518
1519                 bool Iterator::next()
1520                 {
1521                         FLAC__ASSERT(is_valid());
1522                         return (bool)::FLAC__metadata_iterator_next(iterator_);
1523                 }
1524
1525                 bool Iterator::prev()
1526                 {
1527                         FLAC__ASSERT(is_valid());
1528                         return (bool)::FLAC__metadata_iterator_prev(iterator_);
1529                 }
1530
1531                 ::FLAC__MetadataType Iterator::get_block_type() const
1532                 {
1533                         FLAC__ASSERT(is_valid());
1534                         return ::FLAC__metadata_iterator_get_block_type(iterator_);
1535                 }
1536
1537                 Prototype *Iterator::get_block()
1538                 {
1539                         FLAC__ASSERT(is_valid());
1540                         Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
1541                         if(0 != block)
1542                                 block->set_reference(true);
1543                         return block;
1544                 }
1545
1546                 bool Iterator::set_block(Prototype *block)
1547                 {
1548                         FLAC__ASSERT(0 != block);
1549                         FLAC__ASSERT(is_valid());
1550                         bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
1551                         if(ret) {
1552                                 block->set_reference(true);
1553                                 delete block;
1554                         }
1555                         return ret;
1556                 }
1557
1558                 bool Iterator::delete_block(bool replace_with_padding)
1559                 {
1560                         FLAC__ASSERT(is_valid());
1561                         return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
1562                 }
1563
1564                 bool Iterator::insert_block_before(Prototype *block)
1565                 {
1566                         FLAC__ASSERT(0 != block);
1567                         FLAC__ASSERT(is_valid());
1568                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
1569                         if(ret) {
1570                                 block->set_reference(true);
1571                                 delete block;
1572                         }
1573                         return ret;
1574                 }
1575
1576                 bool Iterator::insert_block_after(Prototype *block)
1577                 {
1578                         FLAC__ASSERT(0 != block);
1579                         FLAC__ASSERT(is_valid());
1580                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1581                         if(ret) {
1582                                 block->set_reference(true);
1583                                 delete block;
1584                         }
1585                         return ret;
1586                 }
1587
1588         }
1589 }