libFLAC++: all metadata object operator=() funcs now return *this; add Metadata:...
[flac.git] / src / libFLAC++ / metadata.cpp
1 /* libFLAC++ - Free Lossless Audio Codec library
2  * Copyright (C) 2002,2003,2004  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 #include "FLAC++/metadata.h"
33 #include "FLAC/assert.h"
34 #include <stdlib.h> // for malloc(), free()
35 #include <string.h> // for memcpy() etc.
36
37 #ifdef _MSC_VER
38 // warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
39 #pragma warning ( disable : 4800 )
40 #endif
41
42 namespace FLAC {
43         namespace Metadata {
44
45                 // local utility routines
46
47                 namespace local {
48
49                         Prototype *construct_block(::FLAC__StreamMetadata *object)
50                         {
51                                 Prototype *ret = 0;
52                                 switch(object->type) {
53                                         case FLAC__METADATA_TYPE_STREAMINFO:
54                                                 ret = new StreamInfo(object, /*copy=*/false);
55                                                 break;
56                                         case FLAC__METADATA_TYPE_PADDING:
57                                                 ret = new Padding(object, /*copy=*/false);
58                                                 break;
59                                         case FLAC__METADATA_TYPE_APPLICATION:
60                                                 ret = new Application(object, /*copy=*/false);
61                                                 break;
62                                         case FLAC__METADATA_TYPE_SEEKTABLE:
63                                                 ret = new SeekTable(object, /*copy=*/false);
64                                                 break;
65                                         case FLAC__METADATA_TYPE_VORBIS_COMMENT:
66                                                 ret = new VorbisComment(object, /*copy=*/false);
67                                                 break;
68                                         case FLAC__METADATA_TYPE_CUESHEET:
69                                                 ret = new CueSheet(object, /*copy=*/false);
70                                                 break;
71                                         default:
72                                                 ret = new Unknown(object, /*copy=*/false);
73                                                 break;
74                                 }
75                                 return ret;
76                         }
77
78                 };
79
80                 FLACPP_API Prototype *clone(const Prototype *object)
81                 {
82                         FLAC__ASSERT(0 != object);
83
84                         const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
85                         const Padding *padding = dynamic_cast<const Padding *>(object);
86                         const Application *application = dynamic_cast<const Application *>(object);
87                         const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
88                         const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
89                         const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
90                         const Unknown *unknown = dynamic_cast<const Unknown *>(object);
91
92                         if(0 != streaminfo)
93                                 return new StreamInfo(*streaminfo);
94                         else if(0 != padding)
95                                 return new Padding(*padding);
96                         else if(0 != application)
97                                 return new Application(*application);
98                         else if(0 != seektable)
99                                 return new SeekTable(*seektable);
100                         else if(0 != vorbiscomment)
101                                 return new VorbisComment(*vorbiscomment);
102                         else if(0 != cuesheet)
103                                 return new CueSheet(*cuesheet);
104                         else if(0 != unknown)
105                                 return new Unknown(*unknown);
106                         else {
107                                 FLAC__ASSERT(0);
108                                 return 0;
109                         }
110                 }
111
112                 //
113                 // Prototype
114                 //
115
116                 Prototype::Prototype(const Prototype &object):
117                 object_(::FLAC__metadata_object_clone(object.object_)),
118                 is_reference_(false)
119                 {
120                         FLAC__ASSERT(object.is_valid());
121                 }
122
123                 Prototype::Prototype(const ::FLAC__StreamMetadata &object):
124                 object_(::FLAC__metadata_object_clone(&object)),
125                 is_reference_(false)
126                 {
127                 }
128
129                 Prototype::Prototype(const ::FLAC__StreamMetadata *object):
130                 object_(::FLAC__metadata_object_clone(object)),
131                 is_reference_(false)
132                 {
133                         FLAC__ASSERT(0 != object);
134                 }
135
136                 Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy):
137                 object_(copy? ::FLAC__metadata_object_clone(object) : object),
138                 is_reference_(false)
139                 {
140                         FLAC__ASSERT(0 != object);
141                 }
142
143                 Prototype::~Prototype()
144                 {
145                         clear();
146                 }
147
148                 void Prototype::clear()
149                 {
150                         if(0 != object_ && !is_reference_)
151                                 FLAC__metadata_object_delete(object_);
152                         object_ = 0;
153                 }
154
155                 Prototype &Prototype::operator=(const Prototype &object)
156                 {
157                         FLAC__ASSERT(object.is_valid());
158                         clear();
159                         is_reference_ = false;
160                         object_ = ::FLAC__metadata_object_clone(object.object_);
161                         return *this;
162                 }
163
164                 Prototype &Prototype::operator=(const ::FLAC__StreamMetadata &object)
165                 {
166                         clear();
167                         is_reference_ = false;
168                         object_ = ::FLAC__metadata_object_clone(&object);
169                         return *this;
170                 }
171
172                 Prototype &Prototype::operator=(const ::FLAC__StreamMetadata *object)
173                 {
174                         FLAC__ASSERT(0 != object);
175                         clear();
176                         is_reference_ = false;
177                         object_ = ::FLAC__metadata_object_clone(object);
178                         return *this;
179                 }
180
181                 Prototype &Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy)
182                 {
183                         FLAC__ASSERT(0 != object);
184                         clear();
185                         object_ = (copy? ::FLAC__metadata_object_clone(object) : object);
186                         is_reference_ = false;
187                         return *this;
188                 }
189
190                 bool Prototype::get_is_last() const
191                 {
192                         FLAC__ASSERT(is_valid());
193                         return (bool)object_->is_last;
194                 }
195
196                 FLAC__MetadataType Prototype::get_type() const
197                 {
198                         FLAC__ASSERT(is_valid());
199                         return object_->type;
200                 }
201
202                 unsigned Prototype::get_length() const
203                 {
204                         FLAC__ASSERT(is_valid());
205                         return object_->length;
206                 }
207
208                 void Prototype::set_is_last(bool value)
209                 {
210                         FLAC__ASSERT(is_valid());
211                         object_->is_last = value;
212                 }
213
214
215                 //
216                 // StreamInfo
217                 //
218
219                 StreamInfo::StreamInfo():
220                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
221                 { }
222
223                 StreamInfo::~StreamInfo()
224                 { }
225
226                 unsigned StreamInfo::get_min_blocksize() const
227                 {
228                         FLAC__ASSERT(is_valid());
229                         return object_->data.stream_info.min_blocksize;
230                 }
231
232                 unsigned StreamInfo::get_max_blocksize() const
233                 {
234                         FLAC__ASSERT(is_valid());
235                         return object_->data.stream_info.max_blocksize;
236                 }
237
238                 unsigned StreamInfo::get_min_framesize() const
239                 {
240                         FLAC__ASSERT(is_valid());
241                         return object_->data.stream_info.min_framesize;
242                 }
243
244                 unsigned StreamInfo::get_max_framesize() const
245                 {
246                         FLAC__ASSERT(is_valid());
247                         return object_->data.stream_info.max_framesize;
248                 }
249
250                 unsigned StreamInfo::get_sample_rate() const
251                 {
252                         FLAC__ASSERT(is_valid());
253                         return object_->data.stream_info.sample_rate;
254                 }
255
256                 unsigned StreamInfo::get_channels() const
257                 {
258                         FLAC__ASSERT(is_valid());
259                         return object_->data.stream_info.channels;
260                 }
261
262                 unsigned StreamInfo::get_bits_per_sample() const
263                 {
264                         FLAC__ASSERT(is_valid());
265                         return object_->data.stream_info.bits_per_sample;
266                 }
267
268                 FLAC__uint64 StreamInfo::get_total_samples() const
269                 {
270                         FLAC__ASSERT(is_valid());
271                         return object_->data.stream_info.total_samples;
272                 }
273
274                 const FLAC__byte *StreamInfo::get_md5sum() const
275                 {
276                         FLAC__ASSERT(is_valid());
277                         return object_->data.stream_info.md5sum;
278                 }
279
280                 void StreamInfo::set_min_blocksize(unsigned value)
281                 {
282                         FLAC__ASSERT(is_valid());
283                         FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
284                         FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
285                         object_->data.stream_info.min_blocksize = value;
286                 }
287
288                 void StreamInfo::set_max_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.max_blocksize = value;
294                 }
295
296                 void StreamInfo::set_min_framesize(unsigned value)
297                 {
298                         FLAC__ASSERT(is_valid());
299                         FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
300                         object_->data.stream_info.min_framesize = value;
301                 }
302
303                 void StreamInfo::set_max_framesize(unsigned value)
304                 {
305                         FLAC__ASSERT(is_valid());
306                         FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
307                         object_->data.stream_info.max_framesize = value;
308                 }
309
310                 void StreamInfo::set_sample_rate(unsigned value)
311                 {
312                         FLAC__ASSERT(is_valid());
313                         FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
314                         object_->data.stream_info.sample_rate = value;
315                 }
316
317                 void StreamInfo::set_channels(unsigned value)
318                 {
319                         FLAC__ASSERT(is_valid());
320                         FLAC__ASSERT(value > 0);
321                         FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
322                         object_->data.stream_info.channels = value;
323                 }
324
325                 void StreamInfo::set_bits_per_sample(unsigned value)
326                 {
327                         FLAC__ASSERT(is_valid());
328                         FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
329                         FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
330                         object_->data.stream_info.bits_per_sample = value;
331                 }
332
333                 void StreamInfo::set_total_samples(FLAC__uint64 value)
334                 {
335                         FLAC__ASSERT(is_valid());
336                         FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
337                         object_->data.stream_info.total_samples = value;
338                 }
339
340                 void StreamInfo::set_md5sum(const FLAC__byte value[16])
341                 {
342                         FLAC__ASSERT(is_valid());
343                         FLAC__ASSERT(0 != value);
344                         memcpy(object_->data.stream_info.md5sum, value, 16);
345                 }
346
347
348                 //
349                 // Padding
350                 //
351
352                 Padding::Padding():
353                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
354                 { }
355
356                 Padding::~Padding()
357                 { }
358
359                 void Padding::set_length(unsigned length)
360                 {
361                         FLAC__ASSERT(is_valid());
362                         object_->length = length;
363                 }
364
365
366                 //
367                 // Application
368                 //
369
370                 Application::Application():
371                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
372                 { }
373
374                 Application::~Application()
375                 { }
376
377                 const FLAC__byte *Application::get_id() const
378                 {
379                         FLAC__ASSERT(is_valid());
380                         return object_->data.application.id;
381                 }
382
383                 const FLAC__byte *Application::get_data() const
384                 {
385                         FLAC__ASSERT(is_valid());
386                         return object_->data.application.data;
387                 }
388
389                 void Application::set_id(const FLAC__byte value[4])
390                 {
391                         FLAC__ASSERT(is_valid());
392                         FLAC__ASSERT(0 != value);
393                         memcpy(object_->data.application.id, value, 4);
394                 }
395
396                 bool Application::set_data(const FLAC__byte *data, unsigned length)
397                 {
398                         FLAC__ASSERT(is_valid());
399                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
400                 }
401
402                 bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
403                 {
404                         FLAC__ASSERT(is_valid());
405                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
406                 }
407
408
409                 //
410                 // SeekTable
411                 //
412
413                 SeekTable::SeekTable():
414                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
415                 { }
416
417                 SeekTable::~SeekTable()
418                 { }
419
420                 unsigned SeekTable::get_num_points() const
421                 {
422                         FLAC__ASSERT(is_valid());
423                         return object_->data.seek_table.num_points;
424                 }
425
426                 ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
427                 {
428                         FLAC__ASSERT(is_valid());
429                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
430                         return object_->data.seek_table.points[index];
431                 }
432
433                 void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
434                 {
435                         FLAC__ASSERT(is_valid());
436                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
437                         ::FLAC__metadata_object_seektable_set_point(object_, index, point);
438                 }
439
440                 bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
441                 {
442                         FLAC__ASSERT(is_valid());
443                         FLAC__ASSERT(index <= object_->data.seek_table.num_points);
444                         return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
445                 }
446
447                 bool SeekTable::delete_point(unsigned index)
448                 {
449                         FLAC__ASSERT(is_valid());
450                         FLAC__ASSERT(index < object_->data.seek_table.num_points);
451                         return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
452                 }
453
454                 bool SeekTable::is_legal() const
455                 {
456                         FLAC__ASSERT(is_valid());
457                         return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
458                 }
459
460
461                 //
462                 // VorbisComment::Entry
463                 //
464
465                 VorbisComment::Entry::Entry()
466                 {
467                         zero();
468                 }
469
470                 VorbisComment::Entry::Entry(const char *field, unsigned field_length)
471                 {
472                         zero();
473                         construct(field, field_length);
474                 }
475
476                 VorbisComment::Entry::Entry(const char *field)
477                 {
478                         zero();
479                         construct(field);
480                 }
481
482                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
483                 {
484                         zero();
485                         construct(field_name, field_value, field_value_length);
486                 }
487
488                 VorbisComment::Entry::Entry(const char *field_name, const char *field_value)
489                 {
490                         zero();
491                         construct(field_name, field_value);
492                 }
493
494                 VorbisComment::Entry::Entry(const Entry &entry)
495                 {
496                         FLAC__ASSERT(entry.is_valid());
497                         zero();
498                         construct((const char *)entry.entry_.entry, entry.entry_.length);
499                 }
500
501                 VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
502                 {
503                         FLAC__ASSERT(entry.is_valid());
504                         clear();
505                         construct((const char *)entry.entry_.entry, entry.entry_.length);
506                         return *this;
507                 }
508
509                 VorbisComment::Entry::~Entry()
510                 {
511                         clear();
512                 }
513
514                 bool VorbisComment::Entry::is_valid() const
515                 {
516                         return is_valid_;
517                 }
518
519                 unsigned VorbisComment::Entry::get_field_length() const
520                 {
521                         FLAC__ASSERT(is_valid());
522                         return entry_.length;
523                 }
524
525                 unsigned VorbisComment::Entry::get_field_name_length() const
526                 {
527                         FLAC__ASSERT(is_valid());
528                         return field_name_length_;
529                 }
530
531                 unsigned VorbisComment::Entry::get_field_value_length() const
532                 {
533                         FLAC__ASSERT(is_valid());
534                         return field_value_length_;
535                 }
536
537                 ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
538                 {
539                         FLAC__ASSERT(is_valid());
540                         return entry_;
541                 }
542
543                 const char *VorbisComment::Entry::get_field() const
544                 {
545                         FLAC__ASSERT(is_valid());
546                         return (const char *)entry_.entry;
547                 }
548
549                 const char *VorbisComment::Entry::get_field_name() const
550                 {
551                         FLAC__ASSERT(is_valid());
552                         return field_name_;
553                 }
554
555                 const char *VorbisComment::Entry::get_field_value() const
556                 {
557                         FLAC__ASSERT(is_valid());
558                         return field_value_;
559                 }
560
561                 bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
562                 {
563                         FLAC__ASSERT(is_valid());
564                         FLAC__ASSERT(0 != field);
565
566                         if(!::FLAC__format_vorbiscomment_entry_is_legal((const ::FLAC__byte*)field, field_length))
567                                 return is_valid_ = false;
568
569                         clear_entry();
570
571                         if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length+1))) {
572                                 is_valid_ = false;
573                         }
574                         else {
575                                 entry_.length = field_length;
576                                 memcpy(entry_.entry, field, field_length);
577                                 entry_.entry[field_length] = '\0';
578                                 (void) parse_field();
579                         }
580
581                         return is_valid_;
582                 }
583
584                 bool VorbisComment::Entry::set_field(const char *field)
585                 {
586                         return set_field(field, strlen(field));
587                 }
588
589                 bool VorbisComment::Entry::set_field_name(const char *field_name)
590                 {
591                         FLAC__ASSERT(is_valid());
592                         FLAC__ASSERT(0 != field_name);
593
594                         if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
595                                 return is_valid_ = false;
596
597                         clear_field_name();
598
599                         if(0 == (field_name_ = strdup(field_name))) {
600                                 is_valid_ = false;
601                         }
602                         else {
603                                 field_name_length_ = strlen(field_name_);
604                                 compose_field();
605                         }
606
607                         return is_valid_;
608                 }
609
610                 bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
611                 {
612                         FLAC__ASSERT(is_valid());
613                         FLAC__ASSERT(0 != field_value);
614
615                         if(!::FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte*)field_value, field_value_length))
616                                 return is_valid_ = false;
617
618                         clear_field_value();
619
620                         if(0 == (field_value_ = (char *)malloc(field_value_length+1))) {
621                                 is_valid_ = false;
622                         }
623                         else {
624                                 field_value_length_ = field_value_length;
625                                 memcpy(field_value_, field_value, field_value_length);
626                                 field_value_[field_value_length] = '\0';
627                                 compose_field();
628                         }
629
630                         return is_valid_;
631                 }
632
633                 bool VorbisComment::Entry::set_field_value(const char *field_value)
634                 {
635                         return set_field_value(field_value, strlen(field_value));
636                 }
637
638                 void VorbisComment::Entry::zero()
639                 {
640                         is_valid_ = true;
641                         entry_.length = 0;
642                         entry_.entry = 0;
643                         field_name_ = 0;
644                         field_name_length_ = 0;
645                         field_value_ = 0;
646                         field_value_length_ = 0;
647                 }
648
649                 void VorbisComment::Entry::clear()
650                 {
651                         clear_entry();
652                         clear_field_name();
653                         clear_field_value();
654                         is_valid_ = true;
655                 }
656
657                 void VorbisComment::Entry::clear_entry()
658                 {
659                         if(0 != entry_.entry) {
660                                 free(entry_.entry);
661                                 entry_.entry = 0;
662                                 entry_.length = 0;
663                         }
664                 }
665
666                 void VorbisComment::Entry::clear_field_name()
667                 {
668                         if(0 != field_name_) {
669                                 free(field_name_);
670                                 field_name_ = 0;
671                                 field_name_length_ = 0;
672                         }
673                 }
674
675                 void VorbisComment::Entry::clear_field_value()
676                 {
677                         if(0 != field_value_) {
678                                 free(field_value_);
679                                 field_value_ = 0;
680                                 field_value_length_ = 0;
681                         }
682                 }
683
684                 void VorbisComment::Entry::construct(const char *field, unsigned field_length)
685                 {
686                         if(set_field(field, field_length))
687                                 parse_field();
688                 }
689
690                 void VorbisComment::Entry::construct(const char *field)
691                 {
692                         construct(field, strlen(field));
693                 }
694
695                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
696                 {
697                         if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
698                                 compose_field();
699                 }
700
701                 void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
702                 {
703                         construct(field_name, field_value, strlen(field_value));
704                 }
705
706                 void VorbisComment::Entry::compose_field()
707                 {
708                         clear_entry();
709
710                         if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_ + 1))) {
711                                 is_valid_ = false;
712                         }
713                         else {
714                                 memcpy(entry_.entry, field_name_, field_name_length_);
715                                 entry_.length += field_name_length_;
716                                 memcpy(entry_.entry + entry_.length, "=", 1);
717                                 entry_.length += 1;
718                                 memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
719                                 entry_.length += field_value_length_;
720                                 entry_.entry[entry_.length] = '\0';
721                                 is_valid_ = true;
722                         }
723                 }
724
725                 void VorbisComment::Entry::parse_field()
726                 {
727                         clear_field_name();
728                         clear_field_value();
729
730                         const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
731
732                         if(0 == p)
733                                 p = (const char *)entry_.entry + entry_.length;
734
735                         field_name_length_ = p - (const char *)entry_.entry;
736                         if(0 == (field_name_ = (char *)malloc(field_name_length_ + 1))) { // +1 for the trailing \0
737                                 is_valid_ = false;
738                                 return;
739                         }
740                         memcpy(field_name_, entry_.entry, field_name_length_);
741                         field_name_[field_name_length_] = '\0';
742
743                         if(entry_.length - field_name_length_ == 0) {
744                                 field_value_length_ = 0;
745                                 if(0 == (field_value_ = (char *)malloc(0))) {
746                                         is_valid_ = false;
747                                         return;
748                                 }
749                         }
750                         else {
751                                 field_value_length_ = entry_.length - field_name_length_ - 1;
752                                 if(0 == (field_value_ = (char *)malloc(field_value_length_ + 1))) { // +1 for the trailing \0
753                                         is_valid_ = false;
754                                         return;
755                                 }
756                                 memcpy(field_value_, ++p, field_value_length_);
757                                 field_value_[field_value_length_] = '\0';
758                         }
759
760                         is_valid_ = true;
761                 }
762
763
764                 //
765                 // VorbisComment
766                 //
767
768                 VorbisComment::VorbisComment():
769                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
770                 { }
771
772                 VorbisComment::~VorbisComment()
773                 { }
774
775                 unsigned VorbisComment::get_num_comments() const
776                 {
777                         FLAC__ASSERT(is_valid());
778                         return object_->data.vorbis_comment.num_comments;
779                 }
780
781                 const FLAC__byte *VorbisComment::get_vendor_string() const
782                 {
783                         FLAC__ASSERT(is_valid());
784                         return object_->data.vorbis_comment.vendor_string.entry;
785                 }
786
787                 VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
788                 {
789                         FLAC__ASSERT(is_valid());
790                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
791                         return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
792                 }
793
794                 bool VorbisComment::set_vendor_string(const FLAC__byte *string)
795                 {
796                         FLAC__ASSERT(is_valid());
797                         // vendor_string is a special kind of entry
798                         const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { strlen((const char *)string), (FLAC__byte*)string }; // we can cheat on const-ness because we make a copy below:
799                         return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
800                 }
801
802                 bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
803                 {
804                         FLAC__ASSERT(is_valid());
805                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
806                         return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
807                 }
808
809                 bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
810                 {
811                         FLAC__ASSERT(is_valid());
812                         FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
813                         return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
814                 }
815
816                 bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
817                 {
818                         FLAC__ASSERT(is_valid());
819                         return (bool)::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true);
820                 }
821
822                 bool VorbisComment::delete_comment(unsigned index)
823                 {
824                         FLAC__ASSERT(is_valid());
825                         FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
826                         return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
827                 }
828
829
830                 //
831                 // CueSheet::Track
832                 //
833
834                 CueSheet::Track::Track():
835                 object_(::FLAC__metadata_object_cuesheet_track_new())
836                 { }
837
838                 CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track):
839                 object_(::FLAC__metadata_object_cuesheet_track_clone(track))
840                 { }
841
842                 CueSheet::Track::Track(const Track &track):
843                 object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_))
844                 { }
845
846                 CueSheet::Track &CueSheet::Track::operator=(const Track &track)
847                 {
848                         if(0 != object_)
849                                 ::FLAC__metadata_object_cuesheet_track_delete(object_);
850                         object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_);
851                         return *this;
852                 }
853
854                 CueSheet::Track::~Track()
855                 {
856                         if(0 != object_)
857                                 ::FLAC__metadata_object_cuesheet_track_delete(object_);
858                 }
859
860                 bool CueSheet::Track::is_valid() const
861                 {
862                         return(0 != object_);
863                 }
864
865                 ::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(unsigned i) const
866                 {
867                         FLAC__ASSERT(is_valid());
868                         FLAC__ASSERT(i < object_->num_indices);
869                         return object_->indices[i];
870                 }
871
872                 void CueSheet::Track::set_isrc(const char value[12])
873                 {
874                         FLAC__ASSERT(is_valid());
875                         FLAC__ASSERT(0 != value);
876                         memcpy(object_->isrc, value, 12);
877                         object_->isrc[12] = '\0';
878                 }
879
880                 void CueSheet::Track::set_type(unsigned value)
881                 {
882                         FLAC__ASSERT(is_valid());
883                         FLAC__ASSERT(value <= 1);
884                         object_->type = value;
885                 }
886
887                 void CueSheet::Track::set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index)
888                 {
889                         FLAC__ASSERT(is_valid());
890                         FLAC__ASSERT(i < object_->num_indices);
891                         object_->indices[i] = index;
892                 }
893
894
895                 //
896                 // CueSheet
897                 //
898
899                 CueSheet::CueSheet():
900                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false)
901                 { }
902
903                 CueSheet::~CueSheet()
904                 { }
905
906                 const char *CueSheet::get_media_catalog_number() const
907                 {
908                         FLAC__ASSERT(is_valid());
909                         return object_->data.cue_sheet.media_catalog_number;
910                 }
911
912                 FLAC__uint64 CueSheet::get_lead_in() const
913                 {
914                         FLAC__ASSERT(is_valid());
915                         return object_->data.cue_sheet.lead_in;
916                 }
917
918                 bool CueSheet::get_is_cd() const
919                 {
920                         FLAC__ASSERT(is_valid());
921                         return object_->data.cue_sheet.is_cd? true : false;
922                 }
923
924                 unsigned CueSheet::get_num_tracks() const
925                 {
926                         FLAC__ASSERT(is_valid());
927                         return object_->data.cue_sheet.num_tracks;
928                 }
929
930                 CueSheet::Track CueSheet::get_track(unsigned i) const
931                 {
932                         FLAC__ASSERT(is_valid());
933                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
934                         return Track(object_->data.cue_sheet.tracks + i);
935                 }
936
937                 void CueSheet::set_media_catalog_number(const char value[128])
938                 {
939                         FLAC__ASSERT(is_valid());
940                         FLAC__ASSERT(0 != value);
941                         memcpy(object_->data.cue_sheet.media_catalog_number, value, 128);
942                         object_->data.cue_sheet.media_catalog_number[128] = '\0';
943                 }
944
945                 void CueSheet::set_lead_in(FLAC__uint64 value)
946                 {
947                         FLAC__ASSERT(is_valid());
948                         object_->data.cue_sheet.lead_in = value;
949                 }
950
951                 void CueSheet::set_is_cd(bool value)
952                 {
953                         FLAC__ASSERT(is_valid());
954                         object_->data.cue_sheet.is_cd = value;
955                 }
956
957                 void CueSheet::set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
958                 {
959                         FLAC__ASSERT(is_valid());
960                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
961                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
962                         object_->data.cue_sheet.tracks[track_num].indices[index_num] = index;
963                 }
964
965                 bool CueSheet::insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
966                 {
967                         FLAC__ASSERT(is_valid());
968                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
969                         FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
970                         return (bool)::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, index);
971                 }
972
973                 bool CueSheet::delete_index(unsigned track_num, unsigned index_num)
974                 {
975                         FLAC__ASSERT(is_valid());
976                         FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
977                         FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
978                         return (bool)::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num);
979                 }
980
981                 bool CueSheet::set_track(unsigned i, const CueSheet::Track &track)
982                 {
983                         FLAC__ASSERT(is_valid());
984                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
985                         // We can safely const_cast since copy=true
986                         return (bool)::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
987                 }
988
989                 bool CueSheet::insert_track(unsigned i, const CueSheet::Track &track)
990                 {
991                         FLAC__ASSERT(is_valid());
992                         FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
993                         // We can safely const_cast since copy=true
994                         return (bool)::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
995                 }
996
997                 bool CueSheet::delete_track(unsigned i)
998                 {
999                         FLAC__ASSERT(is_valid());
1000                         FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
1001                         return (bool)::FLAC__metadata_object_cuesheet_delete_track(object_, i);
1002                 }
1003
1004                 bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
1005                 {
1006                         FLAC__ASSERT(is_valid());
1007                         return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
1008                 }
1009
1010
1011                 //
1012                 // Unknown
1013                 //
1014
1015                 Unknown::Unknown():
1016                 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
1017                 { }
1018
1019                 Unknown::~Unknown()
1020                 { }
1021
1022                 const FLAC__byte *Unknown::get_data() const
1023                 {
1024                         FLAC__ASSERT(is_valid());
1025                         return object_->data.application.data;
1026                 }
1027
1028                 bool Unknown::set_data(const FLAC__byte *data, unsigned length)
1029                 {
1030                         FLAC__ASSERT(is_valid());
1031                         return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
1032                 }
1033
1034                 bool Unknown::set_data(FLAC__byte *data, unsigned length, bool copy)
1035                 {
1036                         FLAC__ASSERT(is_valid());
1037                         return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
1038                 }
1039
1040
1041                 // ============================================================
1042                 //
1043                 //  Level 0
1044                 //
1045                 // ============================================================
1046
1047                 FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
1048                 {
1049                         FLAC__ASSERT(0 != filename);
1050
1051                         ::FLAC__StreamMetadata object;
1052
1053                         if(::FLAC__metadata_get_streaminfo(filename, &object)) {
1054                                 streaminfo = object;
1055                                 return true;
1056                         }
1057                         else
1058                                 return false;
1059                 }
1060
1061                 FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
1062                 {
1063                         FLAC__ASSERT(0 != filename);
1064
1065                         ::FLAC__StreamMetadata *object;
1066
1067                         tags = 0;
1068
1069                         if(::FLAC__metadata_get_tags(filename, &object)) {
1070                                 tags = new VorbisComment(object, /*copy=*/false);
1071                                 return true;
1072                         }
1073                         else
1074                                 return false;
1075                 }
1076
1077                 FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
1078                 {
1079                         FLAC__ASSERT(0 != filename);
1080
1081                         ::FLAC__StreamMetadata *object;
1082
1083                         if(::FLAC__metadata_get_tags(filename, &object)) {
1084                                 tags.assign(object, /*copy=*/false);
1085                                 return true;
1086                         }
1087                         else
1088                                 return false;
1089                 }
1090
1091
1092                 // ============================================================
1093                 //
1094                 //  Level 1
1095                 //
1096                 // ============================================================
1097
1098                 SimpleIterator::SimpleIterator():
1099                 iterator_(::FLAC__metadata_simple_iterator_new())
1100                 { }
1101
1102                 SimpleIterator::~SimpleIterator()
1103                 {
1104                         clear();
1105                 }
1106
1107                 void SimpleIterator::clear()
1108                 {
1109                         if(0 != iterator_)
1110                                 FLAC__metadata_simple_iterator_delete(iterator_);
1111                         iterator_ = 0;
1112                 }
1113
1114                 bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
1115                 {
1116                         FLAC__ASSERT(0 != filename);
1117                         FLAC__ASSERT(is_valid());
1118                         return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
1119                 }
1120
1121                 bool SimpleIterator::is_valid() const
1122                 {
1123                         return 0 != iterator_;
1124                 }
1125
1126                 SimpleIterator::Status SimpleIterator::status()
1127                 {
1128                         FLAC__ASSERT(is_valid());
1129                         return Status(::FLAC__metadata_simple_iterator_status(iterator_));
1130                 }
1131
1132                 bool SimpleIterator::is_writable() const
1133                 {
1134                         FLAC__ASSERT(is_valid());
1135                         return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
1136                 }
1137
1138                 bool SimpleIterator::next()
1139                 {
1140                         FLAC__ASSERT(is_valid());
1141                         return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
1142                 }
1143
1144                 bool SimpleIterator::prev()
1145                 {
1146                         FLAC__ASSERT(is_valid());
1147                         return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
1148                 }
1149
1150                 ::FLAC__MetadataType SimpleIterator::get_block_type() const
1151                 {
1152                         FLAC__ASSERT(is_valid());
1153                         return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
1154                 }
1155
1156                 Prototype *SimpleIterator::get_block()
1157                 {
1158                         FLAC__ASSERT(is_valid());
1159                         return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
1160                 }
1161
1162                 bool SimpleIterator::set_block(Prototype *block, bool use_padding)
1163                 {
1164                         FLAC__ASSERT(0 != block);
1165                         FLAC__ASSERT(is_valid());
1166                         return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
1167                 }
1168
1169                 bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
1170                 {
1171                         FLAC__ASSERT(0 != block);
1172                         FLAC__ASSERT(is_valid());
1173                         return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
1174                 }
1175
1176                 bool SimpleIterator::delete_block(bool use_padding)
1177                 {
1178                         FLAC__ASSERT(is_valid());
1179                         return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
1180                 }
1181
1182
1183                 // ============================================================
1184                 //
1185                 //  Level 2
1186                 //
1187                 // ============================================================
1188
1189                 Chain::Chain():
1190                 chain_(::FLAC__metadata_chain_new())
1191                 { }
1192
1193                 Chain::~Chain()
1194                 {
1195                         clear();
1196                 }
1197
1198                 void Chain::clear()
1199                 {
1200                         if(0 != chain_)
1201                                 FLAC__metadata_chain_delete(chain_);
1202                         chain_ = 0;
1203                 }
1204
1205                 bool Chain::is_valid() const
1206                 {
1207                         return 0 != chain_;
1208                 }
1209
1210                 Chain::Status Chain::status()
1211                 {
1212                         FLAC__ASSERT(is_valid());
1213                         return Status(::FLAC__metadata_chain_status(chain_));
1214                 }
1215
1216                 bool Chain::read(const char *filename)
1217                 {
1218                         FLAC__ASSERT(0 != filename);
1219                         FLAC__ASSERT(is_valid());
1220                         return (bool)::FLAC__metadata_chain_read(chain_, filename);
1221                 }
1222
1223                 bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
1224                 {
1225                         FLAC__ASSERT(is_valid());
1226                         return (bool)::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks);
1227                 }
1228
1229                 bool Chain::check_if_tempfile_needed(bool use_padding)
1230                 {
1231                         FLAC__ASSERT(is_valid());
1232                         return (bool)::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
1233                 }
1234
1235                 bool Chain::write(bool use_padding, bool preserve_file_stats)
1236                 {
1237                         FLAC__ASSERT(is_valid());
1238                         return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
1239                 }
1240
1241                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
1242                 {
1243                         FLAC__ASSERT(is_valid());
1244                         return (bool)::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
1245                 }
1246
1247                 bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
1248                 {
1249                         FLAC__ASSERT(is_valid());
1250                         return (bool)::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
1251                 }
1252
1253                 void Chain::merge_padding()
1254                 {
1255                         FLAC__ASSERT(is_valid());
1256                         ::FLAC__metadata_chain_merge_padding(chain_);
1257                 }
1258
1259                 void Chain::sort_padding()
1260                 {
1261                         FLAC__ASSERT(is_valid());
1262                         ::FLAC__metadata_chain_sort_padding(chain_);
1263                 }
1264
1265
1266                 Iterator::Iterator():
1267                 iterator_(::FLAC__metadata_iterator_new())
1268                 { }
1269
1270                 Iterator::~Iterator()
1271                 {
1272                         clear();
1273                 }
1274
1275                 void Iterator::clear()
1276                 {
1277                         if(0 != iterator_)
1278                                 FLAC__metadata_iterator_delete(iterator_);
1279                         iterator_ = 0;
1280                 }
1281
1282                 bool Iterator::is_valid() const
1283                 {
1284                         return 0 != iterator_;
1285                 }
1286
1287                 void Iterator::init(Chain &chain)
1288                 {
1289                         FLAC__ASSERT(is_valid());
1290                         FLAC__ASSERT(chain.is_valid());
1291                         ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
1292                 }
1293
1294                 bool Iterator::next()
1295                 {
1296                         FLAC__ASSERT(is_valid());
1297                         return (bool)::FLAC__metadata_iterator_next(iterator_);
1298                 }
1299
1300                 bool Iterator::prev()
1301                 {
1302                         FLAC__ASSERT(is_valid());
1303                         return (bool)::FLAC__metadata_iterator_prev(iterator_);
1304                 }
1305
1306                 ::FLAC__MetadataType Iterator::get_block_type() const
1307                 {
1308                         FLAC__ASSERT(is_valid());
1309                         return ::FLAC__metadata_iterator_get_block_type(iterator_);
1310                 }
1311
1312                 Prototype *Iterator::get_block()
1313                 {
1314                         FLAC__ASSERT(is_valid());
1315                         Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
1316                         if(0 != block)
1317                                 block->set_reference(true);
1318                         return block;
1319                 }
1320
1321                 bool Iterator::set_block(Prototype *block)
1322                 {
1323                         FLAC__ASSERT(0 != block);
1324                         FLAC__ASSERT(is_valid());
1325                         bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
1326                         if(ret) {
1327                                 block->set_reference(true);
1328                                 delete block;
1329                         }
1330                         return ret;
1331                 }
1332
1333                 bool Iterator::delete_block(bool replace_with_padding)
1334                 {
1335                         FLAC__ASSERT(is_valid());
1336                         return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
1337                 }
1338
1339                 bool Iterator::insert_block_before(Prototype *block)
1340                 {
1341                         FLAC__ASSERT(0 != block);
1342                         FLAC__ASSERT(is_valid());
1343                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
1344                         if(ret) {
1345                                 block->set_reference(true);
1346                                 delete block;
1347                         }
1348                         return ret;
1349                 }
1350
1351                 bool Iterator::insert_block_after(Prototype *block)
1352                 {
1353                         FLAC__ASSERT(0 != block);
1354                         FLAC__ASSERT(is_valid());
1355                         bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1356                         if(ret) {
1357                                 block->set_reference(true);
1358                                 delete block;
1359                         }
1360                         return ret;
1361                 }
1362
1363         };
1364 };