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