metadata.cpp : Fix compiler warning on 64 bit.
[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::insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
1046                 {
1047                         FLAC__ASSERT(is_valid());
1048                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
1049                         FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
1050                         return (bool)::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, index);
1051                 }
1052
1053                 bool CueSheet::delete_index(unsigned track_num, unsigned index_num)
1054                 {
1055                         FLAC__ASSERT(is_valid());
1056                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
1057                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
1058                         return (bool)::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num);
1059                 }
1060
1061                 bool CueSheet::set_track(unsigned i, const CueSheet::Track &track)
1062                 {
1063                         FLAC__ASSERT(is_valid());
1064                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1065                         // We can safely const_cast since copy=true
1066                         return (bool)::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
1067                 }
1068
1069                 bool CueSheet::insert_track(unsigned i, const CueSheet::Track &track)
1070                 {
1071                         FLAC__ASSERT(is_valid());
1072                         FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
1073                         // We can safely const_cast since copy=true
1074                         return (bool)::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
1075                 }
1076
1077                 bool CueSheet::delete_track(unsigned i)
1078                 {
1079                         FLAC__ASSERT(is_valid());
1080                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1081                         return (bool)::FLAC__metadata_object_cuesheet_delete_track(object_, i);
1082                 }
1083
1084                 bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
1085                 {
1086                         FLAC__ASSERT(is_valid());
1087                         return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
1088                 }
1089
1090                 FLAC__uint32 CueSheet::calculate_cddb_id() const
1091                 {
1092                         FLAC__ASSERT(is_valid());
1093                         return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
1094                 }
1095
1096
1097                 //
1098                 // Picture
1099                 //
1100
1101                 Picture::Picture():
1102                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
1103                 { }
1104
1105                 Picture::~Picture()
1106                 { }
1107
1108                 ::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
1109                 {
1110                         FLAC__ASSERT(is_valid());
1111                         return object_->data.picture.type;
1112                 }
1113
1114                 const char *Picture::get_mime_type() const
1115                 {
1116                         FLAC__ASSERT(is_valid());
1117                         return object_->data.picture.mime_type;
1118                 }
1119
1120                 const FLAC__byte *Picture::get_description() const
1121                 {
1122                         FLAC__ASSERT(is_valid());
1123                         return object_->data.picture.description;
1124                 }
1125
1126                 FLAC__uint32 Picture::get_width() const
1127                 {
1128                         FLAC__ASSERT(is_valid());
1129                         return object_->data.picture.width;
1130                 }
1131
1132                 FLAC__uint32 Picture::get_height() const
1133                 {
1134                         FLAC__ASSERT(is_valid());
1135                         return object_->data.picture.height;
1136                 }
1137
1138                 FLAC__uint32 Picture::get_depth() const
1139                 {
1140                         FLAC__ASSERT(is_valid());
1141                         return object_->data.picture.depth;
1142                 }
1143
1144                 FLAC__uint32 Picture::get_colors() const
1145                 {
1146                         FLAC__ASSERT(is_valid());
1147                         return object_->data.picture.colors;
1148                 }
1149
1150                 FLAC__uint32 Picture::get_data_length() const
1151                 {
1152                         FLAC__ASSERT(is_valid());
1153                         return object_->data.picture.data_length;
1154                 }
1155
1156                 const FLAC__byte *Picture::get_data() const
1157                 {
1158                         FLAC__ASSERT(is_valid());
1159                         return object_->data.picture.data;
1160                 }
1161
1162                 void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
1163                 {
1164                         FLAC__ASSERT(is_valid());
1165                         object_->data.picture.type = type;
1166                 }
1167
1168                 bool Picture::set_mime_type(const char *string)
1169                 {
1170                         FLAC__ASSERT(is_valid());
1171                         // We can safely const_cast since copy=true
1172                         return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true);
1173                 }
1174
1175                 bool Picture::set_description(const FLAC__byte *string)
1176                 {
1177                         FLAC__ASSERT(is_valid());
1178                         // We can safely const_cast since copy=true
1179                         return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true);
1180                 }
1181
1182                 void Picture::set_width(FLAC__uint32 value) const
1183                 {
1184                         FLAC__ASSERT(is_valid());
1185                         object_->data.picture.width = value;
1186                 }
1187
1188                 void Picture::set_height(FLAC__uint32 value) const
1189                 {
1190                         FLAC__ASSERT(is_valid());
1191                         object_->data.picture.height = value;
1192                 }
1193
1194                 void Picture::set_depth(FLAC__uint32 value) const
1195                 {
1196                         FLAC__ASSERT(is_valid());
1197                         object_->data.picture.depth = value;
1198                 }
1199
1200                 void Picture::set_colors(FLAC__uint32 value) const
1201                 {
1202                         FLAC__ASSERT(is_valid());
1203                         object_->data.picture.colors = value;
1204                 }
1205
1206                 bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
1207                 {
1208                         FLAC__ASSERT(is_valid());
1209                         // We can safely const_cast since copy=true
1210                         return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
1211                 }
1212
1213
1214                 //
1215                 // Unknown
1216                 //
1217
1218                 Unknown::Unknown():
1219                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
1220                 { }
1221
1222                 Unknown::~Unknown()
1223                 { }
1224
1225                 const FLAC__byte *Unknown::get_data() const
1226                 {
1227                         FLAC__ASSERT(is_valid());
1228                         return object_->data.application.data;
1229                 }
1230
1231                 bool Unknown::set_data(const FLAC__byte *data, unsigned length)
1232                 {
1233                         FLAC__ASSERT(is_valid());
1234                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
1235                 }
1236
1237                 bool Unknown::set_data(FLAC__byte *data, unsigned length, bool copy)
1238                 {
1239                         FLAC__ASSERT(is_valid());
1240                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
1241                 }
1242
1243
1244                 // ============================================================
1245                 //
1246                 //  Level 0
1247                 //
1248                 // ============================================================
1249
1250                 FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
1251                 {
1252                         FLAC__ASSERT(0 != filename);
1253
1254                         ::FLAC__StreamMetadata object;
1255
1256                         if(::FLAC__metadata_get_streaminfo(filename, &object)) {
1257                                 streaminfo = object;
1258                                 return true;
1259                         }
1260                         else
1261                                 return false;
1262                 }
1263
1264                 FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
1265                 {
1266                         FLAC__ASSERT(0 != filename);
1267
1268                         ::FLAC__StreamMetadata *object;
1269
1270                         tags = 0;
1271
1272                         if(::FLAC__metadata_get_tags(filename, &object)) {
1273                                 tags = new VorbisComment(object, /*copy=*/false);
1274                                 return true;
1275                         }
1276                         else
1277                                 return false;
1278                 }
1279
1280                 FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
1281                 {
1282                         FLAC__ASSERT(0 != filename);
1283
1284                         ::FLAC__StreamMetadata *object;
1285
1286                         if(::FLAC__metadata_get_tags(filename, &object)) {
1287                                 tags.assign(object, /*copy=*/false);
1288                                 return true;
1289                         }
1290                         else
1291                                 return false;
1292                 }
1293
1294                 FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
1295                 {
1296                         FLAC__ASSERT(0 != filename);
1297
1298                         ::FLAC__StreamMetadata *object;
1299
1300                         cuesheet = 0;
1301
1302                         if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1303                                 cuesheet = new CueSheet(object, /*copy=*/false);
1304                                 return true;
1305                         }
1306                         else
1307                                 return false;
1308                 }
1309
1310                 FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
1311                 {
1312                         FLAC__ASSERT(0 != filename);
1313
1314                         ::FLAC__StreamMetadata *object;
1315
1316                         if(::FLAC__metadata_get_cuesheet(filename, &object)) {
1317                                 cuesheet.assign(object, /*copy=*/false);
1318                                 return true;
1319                         }
1320                         else
1321                                 return false;
1322                 }
1323
1324                 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)
1325                 {
1326                         FLAC__ASSERT(0 != filename);
1327
1328                         ::FLAC__StreamMetadata *object;
1329
1330                         picture = 0;
1331
1332                         if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1333                                 picture = new Picture(object, /*copy=*/false);
1334                                 return true;
1335                         }
1336                         else
1337                                 return false;
1338                 }
1339
1340                 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)
1341                 {
1342                         FLAC__ASSERT(0 != filename);
1343
1344                         ::FLAC__StreamMetadata *object;
1345
1346                         if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
1347                                 picture.assign(object, /*copy=*/false);
1348                                 return true;
1349                         }
1350                         else
1351                                 return false;
1352                 }
1353
1354
1355                 // ============================================================
1356                 //
1357                 //  Level 1
1358                 //
1359                 // ============================================================
1360
1361                 SimpleIterator::SimpleIterator():
1362                 iterator_(::FLAC__metadata_simple_iterator_new())
1363                 { }
1364
1365                 SimpleIterator::~SimpleIterator()
1366                 {
1367                         clear();
1368                 }
1369
1370                 void SimpleIterator::clear()
1371                 {
1372                         if(0 != iterator_)
1373                                 FLAC__metadata_simple_iterator_delete(iterator_);
1374                         iterator_ = 0;
1375                 }
1376
1377                 bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
1378                 {
1379                         FLAC__ASSERT(0 != filename);
1380                         FLAC__ASSERT(is_valid());
1381                         return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
1382                 }
1383
1384                 bool SimpleIterator::is_valid() const
1385                 {
1386                         return 0 != iterator_;
1387                 }
1388
1389                 SimpleIterator::Status SimpleIterator::status()
1390                 {
1391                         FLAC__ASSERT(is_valid());
1392                         return Status(::FLAC__metadata_simple_iterator_status(iterator_));
1393                 }
1394
1395                 bool SimpleIterator::is_writable() const
1396                 {
1397                         FLAC__ASSERT(is_valid());
1398                         return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
1399                 }
1400
1401                 bool SimpleIterator::next()
1402                 {
1403                         FLAC__ASSERT(is_valid());
1404                         return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
1405                 }
1406
1407                 bool SimpleIterator::prev()
1408                 {
1409                         FLAC__ASSERT(is_valid());
1410                         return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
1411                 }
1412
1413                 //@@@@ add to tests
1414                 bool SimpleIterator::is_last() const
1415                 {
1416                         FLAC__ASSERT(is_valid());
1417                         return (bool)::FLAC__metadata_simple_iterator_is_last(iterator_);
1418                 }
1419
1420                 //@@@@ add to tests
1421                 off_t SimpleIterator::get_block_offset() const
1422                 {
1423                         FLAC__ASSERT(is_valid());
1424                         return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
1425                 }
1426
1427                 ::FLAC__MetadataType SimpleIterator::get_block_type() const
1428                 {
1429                         FLAC__ASSERT(is_valid());
1430                         return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
1431                 }
1432
1433                 //@@@@ add to tests
1434                 unsigned SimpleIterator::get_block_length() const
1435                 {
1436                         FLAC__ASSERT(is_valid());
1437                         return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
1438                 }
1439
1440                 //@@@@ add to tests
1441                 bool SimpleIterator::get_application_id(FLAC__byte *id)
1442                 {
1443                         FLAC__ASSERT(is_valid());
1444                         return (bool)::FLAC__metadata_simple_iterator_get_application_id(iterator_, id);
1445                 }
1446
1447                 Prototype *SimpleIterator::get_block()
1448                 {
1449                         FLAC__ASSERT(is_valid());
1450                         return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
1451                 }
1452
1453                 bool SimpleIterator::set_block(Prototype *block, bool use_padding)
1454                 {
1455                         FLAC__ASSERT(0 != block);
1456                         FLAC__ASSERT(is_valid());
1457                         return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
1458                 }
1459
1460                 bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
1461                 {
1462                         FLAC__ASSERT(0 != block);
1463                         FLAC__ASSERT(is_valid());
1464                         return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
1465                 }
1466
1467                 bool SimpleIterator::delete_block(bool use_padding)
1468                 {
1469                         FLAC__ASSERT(is_valid());
1470                         return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
1471                 }
1472
1473
1474                 // ============================================================
1475                 //
1476                 //  Level 2
1477                 //
1478                 // ============================================================
1479
1480                 Chain::Chain():
1481                 chain_(::FLAC__metadata_chain_new())
1482                 { }
1483
1484                 Chain::~Chain()
1485                 {
1486                         clear();
1487                 }
1488
1489                 void Chain::clear()
1490                 {
1491                         if(0 != chain_)
1492                                 FLAC__metadata_chain_delete(chain_);
1493                         chain_ = 0;
1494                 }
1495
1496                 bool Chain::is_valid() const
1497                 {
1498                         return 0 != chain_;
1499                 }
1500
1501                 Chain::Status Chain::status()
1502                 {
1503                         FLAC__ASSERT(is_valid());
1504                         return Status(::FLAC__metadata_chain_status(chain_));
1505                 }
1506
1507                 bool Chain::read(const char *filename, bool is_ogg)
1508                 {
1509                         FLAC__ASSERT(0 != filename);
1510                         FLAC__ASSERT(is_valid());
1511                         return is_ogg?
1512                                 (bool)::FLAC__metadata_chain_read_ogg(chain_, filename) :
1513                                 (bool)::FLAC__metadata_chain_read(chain_, filename)
1514                         ;
1515                 }
1516
1517                 bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg)
1518                 {
1519                         FLAC__ASSERT(is_valid());
1520                         return is_ogg?
1521                                 (bool)::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks) :
1522                                 (bool)::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks)
1523                         ;
1524                 }
1525
1526                 bool Chain::check_if_tempfile_needed(bool use_padding)
1527                 {
1528                         FLAC__ASSERT(is_valid());
1529                         return (bool)::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
1530                 }
1531
1532                 bool Chain::write(bool use_padding, bool preserve_file_stats)
1533                 {
1534                         FLAC__ASSERT(is_valid());
1535                         return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
1536                 }
1537
1538                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
1539                 {
1540                         FLAC__ASSERT(is_valid());
1541                         return (bool)::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
1542                 }
1543
1544                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
1545                 {
1546                         FLAC__ASSERT(is_valid());
1547                         return (bool)::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
1548                 }
1549
1550                 void Chain::merge_padding()
1551                 {
1552                         FLAC__ASSERT(is_valid());
1553                         ::FLAC__metadata_chain_merge_padding(chain_);
1554                 }
1555
1556                 void Chain::sort_padding()
1557                 {
1558                         FLAC__ASSERT(is_valid());
1559                         ::FLAC__metadata_chain_sort_padding(chain_);
1560                 }
1561
1562
1563                 Iterator::Iterator():
1564                 iterator_(::FLAC__metadata_iterator_new())
1565                 { }
1566
1567                 Iterator::~Iterator()
1568                 {
1569                         clear();
1570                 }
1571
1572                 void Iterator::clear()
1573                 {
1574                         if(0 != iterator_)
1575                                 FLAC__metadata_iterator_delete(iterator_);
1576                         iterator_ = 0;
1577                 }
1578
1579                 bool Iterator::is_valid() const
1580                 {
1581                         return 0 != iterator_;
1582                 }
1583
1584                 void Iterator::init(Chain &chain)
1585                 {
1586                         FLAC__ASSERT(is_valid());
1587                         FLAC__ASSERT(chain.is_valid());
1588                         ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
1589                 }
1590
1591                 bool Iterator::next()
1592                 {
1593                         FLAC__ASSERT(is_valid());
1594                         return (bool)::FLAC__metadata_iterator_next(iterator_);
1595                 }
1596
1597                 bool Iterator::prev()
1598                 {
1599                         FLAC__ASSERT(is_valid());
1600                         return (bool)::FLAC__metadata_iterator_prev(iterator_);
1601                 }
1602
1603                 ::FLAC__MetadataType Iterator::get_block_type() const
1604                 {
1605                         FLAC__ASSERT(is_valid());
1606                         return ::FLAC__metadata_iterator_get_block_type(iterator_);
1607                 }
1608
1609                 Prototype *Iterator::get_block()
1610                 {
1611                         FLAC__ASSERT(is_valid());
1612                         Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
1613                         if(0 != block)
1614                                 block->set_reference(true);
1615                         return block;
1616                 }
1617
1618                 bool Iterator::set_block(Prototype *block)
1619                 {
1620                         FLAC__ASSERT(0 != block);
1621                         FLAC__ASSERT(is_valid());
1622                         bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
1623                         if(ret) {
1624                                 block->set_reference(true);
1625                                 delete block;
1626                         }
1627                         return ret;
1628                 }
1629
1630                 bool Iterator::delete_block(bool replace_with_padding)
1631                 {
1632                         FLAC__ASSERT(is_valid());
1633                         return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
1634                 }
1635
1636                 bool Iterator::insert_block_before(Prototype *block)
1637                 {
1638                         FLAC__ASSERT(0 != block);
1639                         FLAC__ASSERT(is_valid());
1640                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
1641                         if(ret) {
1642                                 block->set_reference(true);
1643                                 delete block;
1644                         }
1645                         return ret;
1646                 }
1647
1648                 bool Iterator::insert_block_after(Prototype *block)
1649                 {
1650                         FLAC__ASSERT(0 != block);
1651                         FLAC__ASSERT(is_valid());
1652                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1653                         if(ret) {
1654                                 block->set_reference(true);
1655                                 delete block;
1656                         }
1657                         return ret;
1658                 }
1659
1660         }
1661 }