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