blob: f9d7325a5fb35d40d951992f91e67e91443b7a37 [file] [log] [blame]
Josh Coalsonfda98fb2002-05-17 06:33:39 +00001/* libFLAC++ - Free Lossless Audio Codec library
2 * Copyright (C) 2002 Josh Coalson
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20#ifndef FLACPP__METADATA_H
21#define FLACPP__METADATA_H
22
23#include "FLAC/metadata.h"
24
Josh Coalsonfb74f102002-05-22 05:33:29 +000025// ===============================================================
26//
27// Full documentation for the metadata interface can be found
28// in the C layer in include/FLAC/metadata.h
29//
30// ===============================================================
31
Josh Coalsonf6efd9c2002-07-27 04:59:54 +000032/** \file include/FLAC++/metadata.h
33 *
34 * \brief
35 * This module provides classes for creating and manipulating FLAC
36 * metadata blocks in memory, and three progressively more powerful
37 * interfaces for traversing and editing metadata in FLAC files.
38 *
39 * See the detailed documentation for each interface in the
40 * \link flacpp_metadata metadata \endlink module.
41 */
42
43/** \defgroup flacpp_metadata FLAC++/metadata.h: metadata interfaces
44 * \ingroup flacpp
45 *
46 * \brief
47 * This module provides classes for creating and manipulating FLAC
48 * metadata blocks in memory, and three progressively more powerful
49 * interfaces for traversing and editing metadata in FLAC files.
50 *
51 * The behavior closely mimics the C layer interface; be sure to read
52 * the detailed description of the
53 * \link flac_metadata C metadata module \endlink.
54 */
55
Josh Coalsonfb74f102002-05-22 05:33:29 +000056
Josh Coalsonfda98fb2002-05-17 06:33:39 +000057namespace FLAC {
58 namespace Metadata {
59
Josh Coalsonfb74f102002-05-22 05:33:29 +000060 // ============================================================
61 //
62 // Metadata objects
63 //
64 // ============================================================
65
Josh Coalsonf6efd9c2002-07-27 04:59:54 +000066 /** \defgroup flacpp_metadata_object FLAC++/metadata.h: metadata object classes
67 * \ingroup flacpp_metadata
68 *
69 * This module contains classes representing FLAC metadata
70 * blocks in memory.
71 *
72 * The behavior closely mimics the C layer interface; be
73 * sure to read the detailed description of the
74 * \link flac_metadata_object C metadata object module \endlink.
75 *
76 * Any time a metadata object is constructed or assigned, you
77 * should check is_valid() to make sure the underlying
78 * ::FLAC__StreamMetadata object was able to be created.
79 *
80 * \warning
81 * When the get_*() methods of any metadata object method
82 * return you a const pointer, DO NOT disobey and write into it.
83 * Always use the set_*() methods.
84 *
85 * \{
86 */
Josh Coalsoncc682512002-06-08 04:53:42 +000087
Josh Coalsonf6efd9c2002-07-27 04:59:54 +000088 /** Base class for all metadata block types.
89 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +000090 class Prototype {
91 protected:
Josh Coalsonf6efd9c2002-07-27 04:59:54 +000092 //@{
93 /** Constructs a copy of the given object. This form
94 * always performs a deep copy.
95 */
96 Prototype(const Prototype &);
97 Prototype(const ::FLAC__StreamMetadata &);
98 Prototype(const ::FLAC__StreamMetadata *);
99 //@}
Josh Coalson83961752002-07-09 06:12:59 +0000100
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000101 /** Constructs an object with copy control. When \a copy
102 * is \c true, behaves identically to
103 * FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object).
104 * When \a copy is \c false, the instance takes ownership of
105 * the pointer and the ::FLAC__StreamMetadata object will
106 * be freed by the destructor.
107 *
108 * \assert
109 * \code object != NULL \endcode
110 */
Josh Coalson83961752002-07-09 06:12:59 +0000111 Prototype(::FLAC__StreamMetadata *object, bool copy);
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000112
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000113 //@{
114 /** Assign from another object. Always performs a deep copy. */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000115 void operator=(const Prototype &);
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000116 void operator=(const ::FLAC__StreamMetadata &);
117 void operator=(const ::FLAC__StreamMetadata *);
118 //@}
Josh Coalson57ba6f42002-06-07 05:27:37 +0000119
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000120 /** Deletes the underlying ::FLAC__StreamMetadata object.
121 */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000122 virtual void clear();
123
Josh Coalsoncc682512002-06-08 04:53:42 +0000124 ::FLAC__StreamMetadata *object_;
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000125 public:
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000126 /** Deletes the underlying ::FLAC__StreamMetadata object.
127 */
Josh Coalson57ba6f42002-06-07 05:27:37 +0000128 virtual ~Prototype();
129
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000130 //@{
131 /** Check for equality, performing a deep compare by following pointers. */
Josh Coalsoncc682512002-06-08 04:53:42 +0000132 inline bool operator==(const Prototype &) const;
133 inline bool operator==(const ::FLAC__StreamMetadata &) const;
134 inline bool operator==(const ::FLAC__StreamMetadata *) const;
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000135 //@}
136
137 //@{
138 /** Check for inequality, performing a deep compare by following pointers. */
Josh Coalsoncc682512002-06-08 04:53:42 +0000139 inline bool operator!=(const Prototype &) const;
140 inline bool operator!=(const ::FLAC__StreamMetadata &) const;
141 inline bool operator!=(const ::FLAC__StreamMetadata *) const;
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000142 //@}
Josh Coalsoncc682512002-06-08 04:53:42 +0000143
Josh Coalsonfb74f102002-05-22 05:33:29 +0000144 friend class SimpleIterator;
145 friend class Iterator;
146
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000147 /** Returns \c true if the object was correctly constructed
148 * (i.e. the underlying ::FLAC__StreamMetadata object was
149 * properly allocated), else \c false.
150 */
Josh Coalson57ba6f42002-06-07 05:27:37 +0000151 inline bool is_valid() const;
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000152
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000153 /** Returns \c true if this block is the last block in a
154 * stream, else \c false.
155 *
156 * \assert
157 * \code is_valid() \endcode
158 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000159 bool get_is_last() const;
Josh Coalsoncc682512002-06-08 04:53:42 +0000160
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000161 /** Returns the type of the block.
162 *
163 * \assert
164 * \code is_valid() \endcode
165 */
166 ::FLAC__MetadataType get_type() const;
167
168 /** Returns the stream length of the metadata block.
169 *
170 * \note
171 * The length does not include the metadata block header,
172 * per spec.
173 *
174 * \assert
175 * \code is_valid() \endcode
176 */
177 unsigned get_length() const;
178
179 /** Sets the "is_last" flag for the block. When using the iterators
180 * it is not necessary to set this flag; they will do it for you.
181 *
182 * \assert
183 * \code is_valid() \endcode
184 */
Josh Coalsoncc682512002-06-08 04:53:42 +0000185 void set_is_last(bool);
Josh Coalsonfb74f102002-05-22 05:33:29 +0000186 private:
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000187 /** Private and undefined so you can't use it. */
188 Prototype();
Josh Coalsonfb74f102002-05-22 05:33:29 +0000189
190 // These are used only by Iterator
191 bool is_reference_;
192 inline void set_reference(bool x) { is_reference_ = x; }
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000193 };
194
Josh Coalson57ba6f42002-06-07 05:27:37 +0000195 inline bool Prototype::operator==(const Prototype &object) const
Josh Coalsond57c8d32002-06-11 06:15:28 +0000196 { return (bool)::FLAC__metadata_object_is_equal(object_, object.object_); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000197
Josh Coalsoncc682512002-06-08 04:53:42 +0000198 inline bool Prototype::operator==(const ::FLAC__StreamMetadata &object) const
Josh Coalsond57c8d32002-06-11 06:15:28 +0000199 { return (bool)::FLAC__metadata_object_is_equal(object_, &object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000200
Josh Coalsoncc682512002-06-08 04:53:42 +0000201 inline bool Prototype::operator==(const ::FLAC__StreamMetadata *object) const
Josh Coalsond57c8d32002-06-11 06:15:28 +0000202 { return (bool)::FLAC__metadata_object_is_equal(object_, object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000203
204 inline bool Prototype::operator!=(const Prototype &object) const
205 { return !operator==(object); }
206
Josh Coalsoncc682512002-06-08 04:53:42 +0000207 inline bool Prototype::operator!=(const ::FLAC__StreamMetadata &object) const
Josh Coalson57ba6f42002-06-07 05:27:37 +0000208 { return !operator==(object); }
209
Josh Coalsoncc682512002-06-08 04:53:42 +0000210 inline bool Prototype::operator!=(const ::FLAC__StreamMetadata *object) const
Josh Coalson57ba6f42002-06-07 05:27:37 +0000211 { return !operator==(object); }
212
213 inline bool Prototype::is_valid() const
214 { return 0 != object_; }
215
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000216 /** Create a deep copy of an object and return it. */
217 Prototype *clone(const Prototype *);
Josh Coalson57ba6f42002-06-07 05:27:37 +0000218
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000219
220 /** STREAMINFO metadata block.
221 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000222 class StreamInfo : public Prototype {
223 public:
224 StreamInfo();
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000225
226 //@{
227 /** Constructs a copy of the given object. This form
228 * always performs a deep copy.
229 */
Josh Coalsoncc682512002-06-08 04:53:42 +0000230 inline StreamInfo(const StreamInfo &object): Prototype(object) { }
231 inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { }
232 inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { }
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000233 //@}
234
235 /** Constructs an object with copy control. See
236 * Prototype(::FLAC__StreamMetadata *object, bool copy).
237 *
238 * \assert
239 * \code object != NULL \endcode
240 */
Josh Coalsoncc682512002-06-08 04:53:42 +0000241 inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000242
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000243 ~StreamInfo();
244
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000245 //@{
246 /** Assign from another object. Always performs a deep copy. */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000247 inline void operator=(const StreamInfo &object) { Prototype::operator=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000248 inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); }
249 inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); }
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000250 //@}
Josh Coalsonfb74f102002-05-22 05:33:29 +0000251
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000252 //@{
253 /** Check for equality, performing a deep compare by following pointers. */
Josh Coalson57ba6f42002-06-07 05:27:37 +0000254 inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000255 inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
256 inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000257 //@}
258
259 //@{
260 /** Check for inequality, performing a deep compare by following pointers. */
Josh Coalson57ba6f42002-06-07 05:27:37 +0000261 inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000262 inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
263 inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000264 //@}
Josh Coalson57ba6f42002-06-07 05:27:37 +0000265
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000266 unsigned get_min_blocksize() const;
267 unsigned get_max_blocksize() const;
268 unsigned get_min_framesize() const;
269 unsigned get_max_framesize() const;
270 unsigned get_sample_rate() const;
271 unsigned get_channels() const;
272 unsigned get_bits_per_sample() const;
273 FLAC__uint64 get_total_samples() const;
274 const FLAC__byte *get_md5sum() const;
275
276 void set_min_blocksize(unsigned value);
277 void set_max_blocksize(unsigned value);
278 void set_min_framesize(unsigned value);
279 void set_max_framesize(unsigned value);
280 void set_sample_rate(unsigned value);
281 void set_channels(unsigned value);
282 void set_bits_per_sample(unsigned value);
283 void set_total_samples(FLAC__uint64 value);
284 void set_md5sum(const FLAC__byte value[16]);
285 };
286
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000287 /** PADDING block.
288 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000289 class Padding : public Prototype {
290 public:
291 Padding();
Josh Coalsoncc682512002-06-08 04:53:42 +0000292 inline Padding(const Padding &object): Prototype(object) { }
293 inline Padding(const ::FLAC__StreamMetadata &object): Prototype(object) { }
294 inline Padding(const ::FLAC__StreamMetadata *object): Prototype(object) { }
295 inline Padding(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000296 ~Padding();
Josh Coalsonfb74f102002-05-22 05:33:29 +0000297
298 inline void operator=(const Padding &object) { Prototype::operator=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000299 inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); }
300 inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); }
Josh Coalsonb2b53582002-05-31 06:20:50 +0000301
Josh Coalson57ba6f42002-06-07 05:27:37 +0000302 inline bool operator==(const Padding &object) const { return Prototype::operator==(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000303 inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
304 inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000305 inline bool operator!=(const Padding &object) const { return Prototype::operator!=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000306 inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
307 inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000308
Josh Coalsonb2b53582002-05-31 06:20:50 +0000309 void set_length(unsigned length);
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000310 };
311
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000312 /** APPLICATION block.
313 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000314 class Application : public Prototype {
315 public:
316 Application();
Josh Coalsoncc682512002-06-08 04:53:42 +0000317 inline Application(const Application &object): Prototype(object) { }
318 inline Application(const ::FLAC__StreamMetadata &object): Prototype(object) { }
319 inline Application(const ::FLAC__StreamMetadata *object): Prototype(object) { }
320 inline Application(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000321 ~Application();
322
Josh Coalsonfb74f102002-05-22 05:33:29 +0000323 inline void operator=(const Application &object) { Prototype::operator=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000324 inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); }
325 inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); }
Josh Coalsonfb74f102002-05-22 05:33:29 +0000326
Josh Coalson57ba6f42002-06-07 05:27:37 +0000327 inline bool operator==(const Application &object) const { return Prototype::operator==(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000328 inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
329 inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000330 inline bool operator!=(const Application &object) const { return Prototype::operator!=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000331 inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
332 inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000333
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000334 const FLAC__byte *get_id() const;
335 const FLAC__byte *get_data() const;
336
Josh Coalsoncc682512002-06-08 04:53:42 +0000337 void set_id(const FLAC__byte value[4]);
338 bool set_data(const FLAC__byte *data, unsigned length); // this form always copies
339 bool set_data(FLAC__byte *data, unsigned length, bool copy);
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000340 };
341
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000342 /** SEEKTABLE block.
343 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000344 class SeekTable : public Prototype {
345 public:
346 SeekTable();
Josh Coalsoncc682512002-06-08 04:53:42 +0000347 inline SeekTable(const SeekTable &object): Prototype(object) { }
348 inline SeekTable(const ::FLAC__StreamMetadata &object): Prototype(object) { }
349 inline SeekTable(const ::FLAC__StreamMetadata *object): Prototype(object) { }
350 inline SeekTable(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000351 ~SeekTable();
Josh Coalsonfb74f102002-05-22 05:33:29 +0000352
353 inline void operator=(const SeekTable &object) { Prototype::operator=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000354 inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); }
355 inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); }
Josh Coalsonb2b53582002-05-31 06:20:50 +0000356
Josh Coalson57ba6f42002-06-07 05:27:37 +0000357 inline bool operator==(const SeekTable &object) const { return Prototype::operator==(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000358 inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
359 inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000360 inline bool operator!=(const SeekTable &object) const { return Prototype::operator!=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000361 inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
362 inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000363
Josh Coalsonb2b53582002-05-31 06:20:50 +0000364 unsigned get_num_points() const;
Josh Coalsoncc682512002-06-08 04:53:42 +0000365 ::FLAC__StreamMetadata_SeekPoint get_point(unsigned index) const;
Josh Coalsonb2b53582002-05-31 06:20:50 +0000366
Josh Coalsoncc682512002-06-08 04:53:42 +0000367 void set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point);
368 bool insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point);
Josh Coalsonb2b53582002-05-31 06:20:50 +0000369 bool delete_point(unsigned index);
Josh Coalson28e08d82002-06-05 05:56:41 +0000370
371 bool is_legal() const;
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000372 };
373
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000374 /** VORBIS_COMMENT block.
375 */
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000376 class VorbisComment : public Prototype {
377 public:
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000378 /** XXX class VorbisComment::Entry
379 */
Josh Coalsonb2b53582002-05-31 06:20:50 +0000380 class Entry {
381 public:
382 Entry();
383 Entry(const char *field, unsigned field_length);
384 Entry(const char *field_name, const char *field_value, unsigned field_value_length);
385 Entry(const Entry &entry);
386 void operator=(const Entry &entry);
387
388 virtual ~Entry();
389
390 virtual bool is_valid() const;
Josh Coalsonb2b53582002-05-31 06:20:50 +0000391
392 unsigned get_field_length() const;
393 unsigned get_field_name_length() const;
394 unsigned get_field_value_length() const;
395
Josh Coalsoncc682512002-06-08 04:53:42 +0000396 ::FLAC__StreamMetadata_VorbisComment_Entry get_entry() const;
Josh Coalsonb2b53582002-05-31 06:20:50 +0000397 const char *get_field() const;
398 const char *get_field_name() const;
399 const char *get_field_value() const;
400
401 bool set_field(const char *field, unsigned field_length);
402 bool set_field_name(const char *field_name);
403 bool set_field_value(const char *field_value, unsigned field_value_length);
404 protected:
405 bool is_valid_;
Josh Coalsoncc682512002-06-08 04:53:42 +0000406 ::FLAC__StreamMetadata_VorbisComment_Entry entry_;
Josh Coalsonb2b53582002-05-31 06:20:50 +0000407 char *field_name_;
408 unsigned field_name_length_;
409 char *field_value_;
410 unsigned field_value_length_;
411 private:
412 void zero();
413 void clear();
414 void clear_entry();
415 void clear_field_name();
416 void clear_field_value();
417 void construct(const char *field, unsigned field_length);
418 void construct(const char *field_name, const char *field_value, unsigned field_value_length);
419 void compose_field();
420 void parse_field();
421 };
422
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000423 VorbisComment();
Josh Coalsoncc682512002-06-08 04:53:42 +0000424 inline VorbisComment(const VorbisComment &object): Prototype(object) { }
425 inline VorbisComment(const ::FLAC__StreamMetadata &object): Prototype(object) { }
426 inline VorbisComment(const ::FLAC__StreamMetadata *object): Prototype(object) { }
427 inline VorbisComment(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000428 ~VorbisComment();
Josh Coalsonfb74f102002-05-22 05:33:29 +0000429
430 inline void operator=(const VorbisComment &object) { Prototype::operator=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000431 inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); }
432 inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); }
Josh Coalsonb2b53582002-05-31 06:20:50 +0000433
Josh Coalson57ba6f42002-06-07 05:27:37 +0000434 inline bool operator==(const VorbisComment &object) const { return Prototype::operator==(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000435 inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
436 inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000437 inline bool operator!=(const VorbisComment &object) const { return Prototype::operator!=(object); }
Josh Coalsoncc682512002-06-08 04:53:42 +0000438 inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
439 inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
Josh Coalson57ba6f42002-06-07 05:27:37 +0000440
Josh Coalsonb2b53582002-05-31 06:20:50 +0000441 unsigned get_num_comments() const;
Josh Coalsoncc682512002-06-08 04:53:42 +0000442 Entry get_vendor_string() const; // only the Entry's field name should be used
Josh Coalsonb2b53582002-05-31 06:20:50 +0000443 Entry get_comment(unsigned index) const;
444
Josh Coalsoncc682512002-06-08 04:53:42 +0000445 bool set_vendor_string(const Entry &entry); // only the Entry's field name will be used
Josh Coalsonb2b53582002-05-31 06:20:50 +0000446 bool set_comment(unsigned index, const Entry &entry);
447 bool insert_comment(unsigned index, const Entry &entry);
448 bool delete_comment(unsigned index);
Josh Coalsonfb74f102002-05-22 05:33:29 +0000449 };
450
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000451 /* \} */
452
Josh Coalsonb2b53582002-05-31 06:20:50 +0000453
Josh Coalsonfb74f102002-05-22 05:33:29 +0000454 // ============================================================
455 //
456 // Level 0
457 //
458 // ============================================================
459
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000460 /** \defgroup flacpp_metadata_level0 FLAC++/metadata.h: metadata level 0 interface
461 * \ingroup flacpp_metadata
462 *
463 * \brief
464 * XXX
465 *
466 * Detailed XXX.
467 *
468 * \{
469 */
470
Josh Coalsonfb74f102002-05-22 05:33:29 +0000471 bool get_streaminfo(const char *filename, StreamInfo &streaminfo);
472
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000473 /* \} */
474
Josh Coalsonb2b53582002-05-31 06:20:50 +0000475
Josh Coalsonfb74f102002-05-22 05:33:29 +0000476 // ============================================================
477 //
478 // Level 1
479 //
480 // ----------------------------------------------------------
481 //
482 // The flow through the iterator in the C++ layer is similar
483 // to the C layer:
484 //
485 // * Create a SimpleIterator instance
486 // * Check SimpleIterator::is_valid()
487 // * Call SimpleIterator::init() and check the return
488 // * Traverse and/or edit. Edits are written to file
489 // immediately.
490 // * Destroy the SimpleIterator instance
491 //
492 // ----------------------------------------------------------
493 //
494 // The ownership of pointers in the C++ layer follows that in
495 // the C layer, i.e.
496 // * The objects returned by get_block() are yours to
497 // modify, but changes are not reflected in the FLAC file
498 // until you call set_block(). The objects are also
499 // yours to delete; they are not automatically deleted
500 // when passed to set_block() or insert_block_after().
501 //
502 // ============================================================
503
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000504 /** \defgroup flacpp_metadata_level1 FLAC++/metadata.h: metadata level 1 interface
505 * \ingroup flacpp_metadata
506 *
507 * \brief
508 * XXX
509 *
510 * Detailed XXX.
511 *
512 * \{
513 */
514
515 /** XXX class SimpleIterator
516 */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000517 class SimpleIterator {
518 public:
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000519 /** XXX class SimpleIterator::Status
520 */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000521 class Status {
522 public:
Josh Coalsoncc682512002-06-08 04:53:42 +0000523 inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { }
524 inline operator ::FLAC__Metadata_SimpleIteratorStatus() const { return status_; }
525 inline const char *as_cstring() const { return ::FLAC__Metadata_SimpleIteratorStatusString[status_]; }
Josh Coalsonfb74f102002-05-22 05:33:29 +0000526 protected:
Josh Coalsoncc682512002-06-08 04:53:42 +0000527 ::FLAC__Metadata_SimpleIteratorStatus status_;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000528 };
529
530 SimpleIterator();
531 virtual ~SimpleIterator();
532
533 bool init(const char *filename, bool preserve_file_stats = false);
534
535 bool is_valid() const;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000536 Status status();
537 bool is_writable() const;
538
539 bool next();
540 bool prev();
541
Josh Coalsoncc682512002-06-08 04:53:42 +0000542 ::FLAC__MetadataType get_block_type() const;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000543 Prototype *get_block();
544 bool set_block(Prototype *block, bool use_padding = true);
545 bool insert_block_after(Prototype *block, bool use_padding = true);
546 bool delete_block(bool use_padding = true);
547
548 protected:
Josh Coalsoncc682512002-06-08 04:53:42 +0000549 ::FLAC__Metadata_SimpleIterator *iterator_;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000550 void clear();
551 };
552
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000553 /* \} */
554
Josh Coalsonb2b53582002-05-31 06:20:50 +0000555
Josh Coalsonfb74f102002-05-22 05:33:29 +0000556 // ============================================================
557 //
558 // Level 2
559 //
560 // ----------------------------------------------------------
561 //
562 // The flow through the iterator in the C++ layer is similar
563 // to the C layer:
564 //
565 // * Create a Chain instance
566 // * Check Chain::is_valid()
567 // * Call Chain::read() and check the return
568 // * Traverse and/or edit with an Iterator or with
569 // Chain::merge_padding() or Chain::sort_padding()
570 // * Write changes back to FLAC file with Chain::write()
571 // * Destroy the Chain instance
572 //
573 // ----------------------------------------------------------
574 //
575 // The ownership of pointers in the C++ layer follows that in
576 // the C layer, i.e.
577 // * The objects returned by Iterator::get_block() are
578 // owned by the iterator and should not be deleted.
579 // When you modify the block, you are directly editing
580 // what's in the chain and do not need to call
581 // Iterator::set_block(). However the changes will not
582 // be reflected in the FLAC file until the chain is
583 // written with Chain::write().
584 //
585 // * When you pass an object to Iterator::set_block(),
586 // Iterator::insert_block_before(), or
587 // Iterator::insert_block_after(), the iterator takes
588 // ownership of the block and it will be deleted with the
589 // chain.
590 //
591 // ============================================================
592
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000593 /** \defgroup flacpp_metadata_level2 FLAC++/metadata.h: metadata level 2 interface
594 * \ingroup flacpp_metadata
595 *
596 * \brief
597 * XXX
598 *
599 * Detailed XXX.
600 *
601 * \{
602 */
603
604 /** XXX class Chain
605 */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000606 class Chain {
607 public:
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000608 /** XXX class Chain::Status
609 */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000610 class Status {
611 public:
Josh Coalsoncc682512002-06-08 04:53:42 +0000612 inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { }
613 inline operator ::FLAC__Metadata_ChainStatus() const { return status_; }
614 inline const char *as_cstring() const { return ::FLAC__Metadata_ChainStatusString[status_]; }
Josh Coalsonfb74f102002-05-22 05:33:29 +0000615 protected:
Josh Coalsoncc682512002-06-08 04:53:42 +0000616 ::FLAC__Metadata_ChainStatus status_;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000617 };
618
619 Chain();
620 virtual ~Chain();
621
622 friend class Iterator;
623
624 bool is_valid() const;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000625 Status status();
626
627 bool read(const char *filename);
628 bool write(bool use_padding = true, bool preserve_file_stats = false);
629
630 void merge_padding();
631 void sort_padding();
632
633 protected:
Josh Coalsoncc682512002-06-08 04:53:42 +0000634 ::FLAC__Metadata_Chain *chain_;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000635 virtual void clear();
636 };
637
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000638 /** XXX class Iterator
639 */
Josh Coalsonfb74f102002-05-22 05:33:29 +0000640 class Iterator {
641 public:
642 Iterator();
643 virtual ~Iterator();
644
645 bool is_valid() const;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000646
Josh Coalson999be3b2002-06-10 04:42:35 +0000647 void init(Chain &chain);
Josh Coalsonfb74f102002-05-22 05:33:29 +0000648
649 bool next();
650 bool prev();
651
Josh Coalsoncc682512002-06-08 04:53:42 +0000652 ::FLAC__MetadataType get_block_type() const;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000653 Prototype *get_block();
654 bool set_block(Prototype *block);
655 bool delete_block(bool replace_with_padding);
656 bool insert_block_before(Prototype *block);
657 bool insert_block_after(Prototype *block);
658
659 protected:
Josh Coalsoncc682512002-06-08 04:53:42 +0000660 ::FLAC__Metadata_Iterator *iterator_;
Josh Coalsonfb74f102002-05-22 05:33:29 +0000661 virtual void clear();
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000662 };
663
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000664 /* \} */
665
Josh Coalsonfda98fb2002-05-17 06:33:39 +0000666 };
667};
668
669#endif
Josh Coalsonf6efd9c2002-07-27 04:59:54 +0000670#if 0
671 Prototype *clone(const Prototype *object)
672 {
673 FLAC__ASSERT(0 != object);
674
675 const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
676 const Padding *padding = dynamic_cast<const Padding *>(object);
677 const Application *application = dynamic_cast<const Application *>(object);
678 const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
679 const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
680
681 if(0 != streaminfo)
682 return new StreamInfo(*streaminfo);
683 else if(0 != padding)
684 return new Padding(*padding);
685 else if(0 != application)
686 return new Application(*application);
687 else if(0 != seektable)
688 return new SeekTable(*seektable);
689 else if(0 != vorbiscomment)
690 return new VorbisComment(*vorbiscomment);
691 else {
692 FLAC__ASSERT(0);
693 return 0;
694 }
695 }
696
697 //
698 // StreamInfo
699 //
700
701 StreamInfo::StreamInfo():
702 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
703 { }
704
705 StreamInfo::~StreamInfo()
706 { }
707
708 unsigned StreamInfo::get_min_blocksize() const
709 {
710 FLAC__ASSERT(is_valid());
711 return object_->data.stream_info.min_blocksize;
712 }
713
714 unsigned StreamInfo::get_max_blocksize() const
715 {
716 FLAC__ASSERT(is_valid());
717 return object_->data.stream_info.max_blocksize;
718 }
719
720 unsigned StreamInfo::get_min_framesize() const
721 {
722 FLAC__ASSERT(is_valid());
723 return object_->data.stream_info.min_framesize;
724 }
725
726 unsigned StreamInfo::get_max_framesize() const
727 {
728 FLAC__ASSERT(is_valid());
729 return object_->data.stream_info.max_framesize;
730 }
731
732 unsigned StreamInfo::get_sample_rate() const
733 {
734 FLAC__ASSERT(is_valid());
735 return object_->data.stream_info.sample_rate;
736 }
737
738 unsigned StreamInfo::get_channels() const
739 {
740 FLAC__ASSERT(is_valid());
741 return object_->data.stream_info.channels;
742 }
743
744 unsigned StreamInfo::get_bits_per_sample() const
745 {
746 FLAC__ASSERT(is_valid());
747 return object_->data.stream_info.bits_per_sample;
748 }
749
750 FLAC__uint64 StreamInfo::get_total_samples() const
751 {
752 FLAC__ASSERT(is_valid());
753 return object_->data.stream_info.total_samples;
754 }
755
756 const FLAC__byte *StreamInfo::get_md5sum() const
757 {
758 FLAC__ASSERT(is_valid());
759 return object_->data.stream_info.md5sum;
760 }
761
762 void StreamInfo::set_min_blocksize(unsigned value)
763 {
764 FLAC__ASSERT(is_valid());
765 FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
766 FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
767 object_->data.stream_info.min_blocksize = value;
768 }
769
770 void StreamInfo::set_max_blocksize(unsigned value)
771 {
772 FLAC__ASSERT(is_valid());
773 FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
774 FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
775 object_->data.stream_info.max_blocksize = value;
776 }
777
778 void StreamInfo::set_min_framesize(unsigned value)
779 {
780 FLAC__ASSERT(is_valid());
781 FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
782 object_->data.stream_info.min_framesize = value;
783 }
784
785 void StreamInfo::set_max_framesize(unsigned value)
786 {
787 FLAC__ASSERT(is_valid());
788 FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
789 object_->data.stream_info.max_framesize = value;
790 }
791
792 void StreamInfo::set_sample_rate(unsigned value)
793 {
794 FLAC__ASSERT(is_valid());
795 FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
796 object_->data.stream_info.sample_rate = value;
797 }
798
799 void StreamInfo::set_channels(unsigned value)
800 {
801 FLAC__ASSERT(is_valid());
802 FLAC__ASSERT(value > 0);
803 FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
804 object_->data.stream_info.channels = value;
805 }
806
807 void StreamInfo::set_bits_per_sample(unsigned value)
808 {
809 FLAC__ASSERT(is_valid());
810 FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
811 FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
812 object_->data.stream_info.bits_per_sample = value;
813 }
814
815 void StreamInfo::set_total_samples(FLAC__uint64 value)
816 {
817 FLAC__ASSERT(is_valid());
818 FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
819 object_->data.stream_info.total_samples = value;
820 }
821
822 void StreamInfo::set_md5sum(const FLAC__byte value[16])
823 {
824 FLAC__ASSERT(is_valid());
825 FLAC__ASSERT(0 != value);
826 memcpy(object_->data.stream_info.md5sum, value, 16);
827 }
828
829
830 //
831 // Padding
832 //
833
834 Padding::Padding():
835 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
836 { }
837
838 Padding::~Padding()
839 { }
840
841 void Padding::set_length(unsigned length)
842 {
843 FLAC__ASSERT(is_valid());
844 object_->length = length;
845 }
846
847
848 //
849 // Application
850 //
851
852 Application::Application():
853 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
854 { }
855
856 Application::~Application()
857 { }
858
859 const FLAC__byte *Application::get_id() const
860 {
861 FLAC__ASSERT(is_valid());
862 return object_->data.application.id;
863 }
864
865 const FLAC__byte *Application::get_data() const
866 {
867 FLAC__ASSERT(is_valid());
868 return object_->data.application.data;
869 }
870
871 void Application::set_id(const FLAC__byte value[4])
872 {
873 FLAC__ASSERT(is_valid());
874 FLAC__ASSERT(0 != value);
875 memcpy(object_->data.application.id, value, 4);
876 }
877
878 bool Application::set_data(const FLAC__byte *data, unsigned length)
879 {
880 FLAC__ASSERT(is_valid());
881 return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
882 }
883
884 bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
885 {
886 FLAC__ASSERT(is_valid());
887 return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
888 }
889
890
891 //
892 // SeekTable
893 //
894
895 SeekTable::SeekTable():
896 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
897 { }
898
899 SeekTable::~SeekTable()
900 { }
901
902 unsigned SeekTable::get_num_points() const
903 {
904 FLAC__ASSERT(is_valid());
905 return object_->data.seek_table.num_points;
906 }
907
908 ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
909 {
910 FLAC__ASSERT(is_valid());
911 FLAC__ASSERT(index < object_->data.seek_table.num_points);
912 return object_->data.seek_table.points[index];
913 }
914
915 void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
916 {
917 FLAC__ASSERT(is_valid());
918 FLAC__ASSERT(index < object_->data.seek_table.num_points);
919 ::FLAC__metadata_object_seektable_set_point(object_, index, point);
920 }
921
922 bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
923 {
924 FLAC__ASSERT(is_valid());
925 FLAC__ASSERT(index <= object_->data.seek_table.num_points);
926 return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
927 }
928
929 bool SeekTable::delete_point(unsigned index)
930 {
931 FLAC__ASSERT(is_valid());
932 FLAC__ASSERT(index < object_->data.seek_table.num_points);
933 return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
934 }
935
936 bool SeekTable::is_legal() const
937 {
938 FLAC__ASSERT(is_valid());
939 return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
940 }
941
942
943 //
944 // VorbisComment::Entry
945 //
946
947 VorbisComment::Entry::Entry()
948 {
949 zero();
950 }
951
952 VorbisComment::Entry::Entry(const char *field, unsigned field_length)
953 {
954 zero();
955 construct(field, field_length);
956 }
957
958 VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
959 {
960 zero();
961 construct(field_name, field_value, field_value_length);
962 }
963
964 VorbisComment::Entry::Entry(const Entry &entry)
965 {
966 FLAC__ASSERT(entry.is_valid());
967 zero();
968 construct((const char *)entry.entry_.entry, entry.entry_.length);
969 }
970
971 void VorbisComment::Entry::operator=(const Entry &entry)
972 {
973 FLAC__ASSERT(entry.is_valid());
974 clear();
975 construct((const char *)entry.entry_.entry, entry.entry_.length);
976 }
977
978 VorbisComment::Entry::~Entry()
979 {
980 clear();
981 }
982
983 bool VorbisComment::Entry::is_valid() const
984 {
985 return is_valid_;
986 }
987
988 unsigned VorbisComment::Entry::get_field_length() const
989 {
990 FLAC__ASSERT(is_valid());
991 return entry_.length;
992 }
993
994 unsigned VorbisComment::Entry::get_field_name_length() const
995 {
996 FLAC__ASSERT(is_valid());
997 return field_name_length_;
998 }
999
1000 unsigned VorbisComment::Entry::get_field_value_length() const
1001 {
1002 FLAC__ASSERT(is_valid());
1003 return field_value_length_;
1004 }
1005
1006 ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
1007 {
1008 FLAC__ASSERT(is_valid());
1009 return entry_;
1010 }
1011
1012 const char *VorbisComment::Entry::get_field() const
1013 {
1014 FLAC__ASSERT(is_valid());
1015 return (const char *)entry_.entry;
1016 }
1017
1018 const char *VorbisComment::Entry::get_field_name() const
1019 {
1020 FLAC__ASSERT(is_valid());
1021 return field_name_;
1022 }
1023
1024 const char *VorbisComment::Entry::get_field_value() const
1025 {
1026 FLAC__ASSERT(is_valid());
1027 return field_value_;
1028 }
1029
1030 bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
1031 {
1032 FLAC__ASSERT(is_valid());
1033 FLAC__ASSERT(0 != field);
1034
1035 clear_entry();
1036
1037 if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length))) {
1038 is_valid_ = false;
1039 }
1040 else {
1041 entry_.length = field_length;
1042 memcpy(entry_.entry, field, field_length);
1043 (void) parse_field();
1044 }
1045
1046 return is_valid_;
1047 }
1048
1049 bool VorbisComment::Entry::set_field_name(const char *field_name)
1050 {
1051 FLAC__ASSERT(is_valid());
1052 FLAC__ASSERT(0 != field_name);
1053
1054 clear_field_name();
1055
1056 if(0 == (field_name_ = strdup(field_name))) {
1057 is_valid_ = false;
1058 }
1059 else {
1060 field_name_length_ = strlen(field_name_);
1061 compose_field();
1062 }
1063
1064 return is_valid_;
1065 }
1066
1067 bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
1068 {
1069 FLAC__ASSERT(is_valid());
1070 FLAC__ASSERT(0 != field_value);
1071
1072 clear_field_value();
1073
1074 if(0 == (field_value_ = (char *)malloc(field_value_length))) {
1075 is_valid_ = false;
1076 }
1077 else {
1078 field_value_length_ = field_value_length;
1079 memcpy(field_value_, field_value, field_value_length);
1080 compose_field();
1081 }
1082
1083 return is_valid_;
1084 }
1085
1086 void VorbisComment::Entry::zero()
1087 {
1088 is_valid_ = true;
1089 entry_.length = 0;
1090 entry_.entry = 0;
1091 field_name_ = 0;
1092 field_name_length_ = 0;
1093 field_value_ = 0;
1094 field_value_length_ = 0;
1095 }
1096
1097 void VorbisComment::Entry::clear()
1098 {
1099 clear_entry();
1100 clear_field_name();
1101 clear_field_value();
1102 is_valid_ = true;
1103 }
1104
1105 void VorbisComment::Entry::clear_entry()
1106 {
1107 if(0 != entry_.entry) {
1108 free(entry_.entry);
1109 entry_.entry = 0;
1110 entry_.length = 0;
1111 }
1112 }
1113
1114 void VorbisComment::Entry::clear_field_name()
1115 {
1116 if(0 != field_name_) {
1117 free(field_name_);
1118 field_name_ = 0;
1119 field_name_length_ = 0;
1120 }
1121 }
1122
1123 void VorbisComment::Entry::clear_field_value()
1124 {
1125 if(0 != field_value_) {
1126 free(field_value_);
1127 field_value_ = 0;
1128 field_value_length_ = 0;
1129 }
1130 }
1131
1132 void VorbisComment::Entry::construct(const char *field, unsigned field_length)
1133 {
1134 if(set_field(field, field_length))
1135 parse_field();
1136 }
1137
1138 void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
1139 {
1140 if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
1141 compose_field();
1142 }
1143
1144 void VorbisComment::Entry::compose_field()
1145 {
1146 clear_entry();
1147
1148 if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_))) {
1149 is_valid_ = false;
1150 }
1151 else {
1152 memcpy(entry_.entry, field_name_, field_name_length_);
1153 entry_.length += field_name_length_;
1154 memcpy(entry_.entry + entry_.length, "=", 1);
1155 entry_.length += 1;
1156 memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
1157 entry_.length += field_value_length_;
1158 is_valid_ = true;
1159 }
1160 }
1161
1162 void VorbisComment::Entry::parse_field()
1163 {
1164 clear_field_name();
1165 clear_field_value();
1166
1167 const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
1168
1169 if(0 == p)
1170 p = (const char *)entry_.entry + entry_.length;
1171
1172 field_name_length_ = p - (const char *)entry_.entry;
1173 if(0 == (field_name_ = (char *)malloc(field_name_length_ + 1))) { // +1 for the trailing \0
1174 is_valid_ = false;
1175 return;
1176 }
1177 memcpy(field_name_, entry_.entry, field_name_length_);
1178 field_name_[field_name_length_] = '\0';
1179
1180 if(entry_.length - field_name_length_ == 0) {
1181 field_value_length_ = 0;
1182 if(0 == (field_value_ = (char *)malloc(0))) {
1183 is_valid_ = false;
1184 return;
1185 }
1186 }
1187 else {
1188 field_value_length_ = entry_.length - field_name_length_ - 1;
1189 if(0 == (field_value_ = (char *)malloc(field_value_length_))) {
1190 is_valid_ = false;
1191 return;
1192 }
1193 memcpy(field_value_, ++p, field_value_length_);
1194 }
1195
1196 is_valid_ = true;
1197 }
1198
1199
1200 //
1201 // VorbisComment
1202 //
1203
1204 VorbisComment::VorbisComment():
1205 Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
1206 { }
1207
1208 VorbisComment::~VorbisComment()
1209 { }
1210
1211 unsigned VorbisComment::get_num_comments() const
1212 {
1213 FLAC__ASSERT(is_valid());
1214 return object_->data.vorbis_comment.num_comments;
1215 }
1216
1217 VorbisComment::Entry VorbisComment::get_vendor_string() const
1218 {
1219 FLAC__ASSERT(is_valid());
1220 return Entry((const char *)object_->data.vorbis_comment.vendor_string.entry, object_->data.vorbis_comment.vendor_string.length);
1221 }
1222
1223 VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
1224 {
1225 FLAC__ASSERT(is_valid());
1226 FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
1227 return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
1228 }
1229
1230 bool VorbisComment::set_vendor_string(const VorbisComment::Entry &entry)
1231 {
1232 FLAC__ASSERT(is_valid());
1233 // vendor_string is a special kind of entry
1234 ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
1235 vendor_string.length = entry.get_field_name_length();
1236 vendor_string.entry = (FLAC__byte*)entry.get_field_name(); // we can cheat on const-ness because we make a copy below:
1237 return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
1238 }
1239
1240 bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
1241 {
1242 FLAC__ASSERT(is_valid());
1243 FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
1244 return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
1245 }
1246
1247 bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
1248 {
1249 FLAC__ASSERT(is_valid());
1250 FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
1251 return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
1252 }
1253
1254 bool VorbisComment::delete_comment(unsigned index)
1255 {
1256 FLAC__ASSERT(is_valid());
1257 FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
1258 return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
1259 }
1260
1261
1262 // ============================================================
1263 //
1264 // Level 0
1265 //
1266 // ============================================================
1267
1268 bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
1269 {
1270 FLAC__ASSERT(0 != filename);
1271
1272 ::FLAC__StreamMetadata s;
1273
1274 if(::FLAC__metadata_get_streaminfo(filename, &s)) {
1275 streaminfo = s;
1276 return true;
1277 }
1278 else
1279 return false;
1280 }
1281
1282
1283 // ============================================================
1284 //
1285 // Level 1
1286 //
1287 // ============================================================
1288
1289 SimpleIterator::SimpleIterator():
1290 iterator_(::FLAC__metadata_simple_iterator_new())
1291 { }
1292
1293 SimpleIterator::~SimpleIterator()
1294 {
1295 clear();
1296 }
1297
1298 void SimpleIterator::clear()
1299 {
1300 if(0 != iterator_)
1301 FLAC__metadata_simple_iterator_delete(iterator_);
1302 iterator_ = 0;
1303 }
1304
1305 bool SimpleIterator::init(const char *filename, bool preserve_file_stats)
1306 {
1307 FLAC__ASSERT(0 != filename);
1308 FLAC__ASSERT(is_valid());
1309 return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, preserve_file_stats);
1310 }
1311
1312 bool SimpleIterator::is_valid() const
1313 {
1314 return 0 != iterator_;
1315 }
1316
1317 SimpleIterator::Status SimpleIterator::status()
1318 {
1319 FLAC__ASSERT(is_valid());
1320 return Status(::FLAC__metadata_simple_iterator_status(iterator_));
1321 }
1322
1323 bool SimpleIterator::is_writable() const
1324 {
1325 FLAC__ASSERT(is_valid());
1326 return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
1327 }
1328
1329 bool SimpleIterator::next()
1330 {
1331 FLAC__ASSERT(is_valid());
1332 return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
1333 }
1334
1335 bool SimpleIterator::prev()
1336 {
1337 FLAC__ASSERT(is_valid());
1338 return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
1339 }
1340
1341 ::FLAC__MetadataType SimpleIterator::get_block_type() const
1342 {
1343 FLAC__ASSERT(is_valid());
1344 return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
1345 }
1346
1347 Prototype *SimpleIterator::get_block()
1348 {
1349 FLAC__ASSERT(is_valid());
1350 return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
1351 }
1352
1353 bool SimpleIterator::set_block(Prototype *block, bool use_padding)
1354 {
1355 FLAC__ASSERT(0 != block);
1356 FLAC__ASSERT(is_valid());
1357 return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
1358 }
1359
1360 bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
1361 {
1362 FLAC__ASSERT(0 != block);
1363 FLAC__ASSERT(is_valid());
1364 return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
1365 }
1366
1367 bool SimpleIterator::delete_block(bool use_padding)
1368 {
1369 FLAC__ASSERT(is_valid());
1370 return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
1371 }
1372
1373
1374 // ============================================================
1375 //
1376 // Level 2
1377 //
1378 // ============================================================
1379
1380 Chain::Chain():
1381 chain_(::FLAC__metadata_chain_new())
1382 { }
1383
1384 Chain::~Chain()
1385 {
1386 clear();
1387 }
1388
1389 void Chain::clear()
1390 {
1391 if(0 != chain_)
1392 FLAC__metadata_chain_delete(chain_);
1393 chain_ = 0;
1394 }
1395
1396 bool Chain::is_valid() const
1397 {
1398 return 0 != chain_;
1399 }
1400
1401 Chain::Status Chain::status()
1402 {
1403 FLAC__ASSERT(is_valid());
1404 return Status(::FLAC__metadata_chain_status(chain_));
1405 }
1406
1407 bool Chain::read(const char *filename)
1408 {
1409 FLAC__ASSERT(0 != filename);
1410 FLAC__ASSERT(is_valid());
1411 return (bool)::FLAC__metadata_chain_read(chain_, filename);
1412 }
1413
1414 bool Chain::write(bool use_padding, bool preserve_file_stats)
1415 {
1416 FLAC__ASSERT(is_valid());
1417 return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
1418 }
1419
1420 void Chain::merge_padding()
1421 {
1422 FLAC__ASSERT(is_valid());
1423 ::FLAC__metadata_chain_merge_padding(chain_);
1424 }
1425
1426 void Chain::sort_padding()
1427 {
1428 FLAC__ASSERT(is_valid());
1429 ::FLAC__metadata_chain_sort_padding(chain_);
1430 }
1431
1432
1433 Iterator::Iterator():
1434 iterator_(::FLAC__metadata_iterator_new())
1435 { }
1436
1437 Iterator::~Iterator()
1438 {
1439 clear();
1440 }
1441
1442 void Iterator::clear()
1443 {
1444 if(0 != iterator_)
1445 FLAC__metadata_iterator_delete(iterator_);
1446 iterator_ = 0;
1447 }
1448
1449 bool Iterator::is_valid() const
1450 {
1451 return 0 != iterator_;
1452 }
1453
1454 void Iterator::init(Chain &chain)
1455 {
1456 FLAC__ASSERT(is_valid());
1457 FLAC__ASSERT(chain.is_valid());
1458 ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
1459 }
1460
1461 bool Iterator::next()
1462 {
1463 FLAC__ASSERT(is_valid());
1464 return (bool)::FLAC__metadata_iterator_next(iterator_);
1465 }
1466
1467 bool Iterator::prev()
1468 {
1469 FLAC__ASSERT(is_valid());
1470 return (bool)::FLAC__metadata_iterator_prev(iterator_);
1471 }
1472
1473 ::FLAC__MetadataType Iterator::get_block_type() const
1474 {
1475 FLAC__ASSERT(is_valid());
1476 return ::FLAC__metadata_iterator_get_block_type(iterator_);
1477 }
1478
1479 Prototype *Iterator::get_block()
1480 {
1481 FLAC__ASSERT(is_valid());
1482 Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
1483 if(0 != block)
1484 block->set_reference(true);
1485 return block;
1486 }
1487
1488 bool Iterator::set_block(Prototype *block)
1489 {
1490 FLAC__ASSERT(0 != block);
1491 FLAC__ASSERT(is_valid());
1492 bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
1493 if(ret) {
1494 block->set_reference(true);
1495 delete block;
1496 }
1497 return ret;
1498 }
1499
1500 bool Iterator::delete_block(bool replace_with_padding)
1501 {
1502 FLAC__ASSERT(is_valid());
1503 return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
1504 }
1505
1506 bool Iterator::insert_block_before(Prototype *block)
1507 {
1508 FLAC__ASSERT(0 != block);
1509 FLAC__ASSERT(is_valid());
1510 bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
1511 if(ret) {
1512 block->set_reference(true);
1513 delete block;
1514 }
1515 return ret;
1516 }
1517
1518 bool Iterator::insert_block_after(Prototype *block)
1519 {
1520 FLAC__ASSERT(0 != block);
1521 FLAC__ASSERT(is_valid());
1522 bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
1523 if(ret) {
1524 block->set_reference(true);
1525 delete block;
1526 }
1527 return ret;
1528 }
1529
1530 };
1531};
1532#endif