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