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