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