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