diff --git a/include/FLAC++/all.h b/include/FLAC++/all.h index 02c43b40..ab919780 100644 --- a/include/FLAC++/all.h +++ b/include/FLAC++/all.h @@ -24,4 +24,12 @@ #include "decoder.h" #include "metadata.h" +/** \defgroup flacpp FLAC C++ API + * + * The FLAC C++ API is the interface to libFLAC++, a set of classes + * that encapsulate the encoders, decoders, and metadata interfaces + * in libFLAC. + * + */ + #endif diff --git a/include/FLAC++/decoder.h b/include/FLAC++/decoder.h index de8884d9..e665c0a5 100644 --- a/include/FLAC++/decoder.h +++ b/include/FLAC++/decoder.h @@ -32,6 +32,25 @@ // =============================================================== +/** \file include/FLAC++/decoder.h + * + * \brief + * This file contains the classes which implement the various + * decoders. + * + * See the detailed documentation in the + * \link flacpp_decoder decoder \endlink module. + */ + +/** \defgroup flacpp_decoder FLAC++/decoder.h: decoder classes + * \ingroup flacpp + * + * \brief + * Brief XXX. + * + * Detailed decoder XXX. + */ + namespace FLAC { namespace Decoder { @@ -51,6 +70,18 @@ namespace FLAC { // // ============================================================ + /** \defgroup flacpp_stream_decoder FLAC++/decoder.h: stream decoder class + * \ingroup flacpp_decoder + * + * \brief + * Brief XXX. + * + * Detailed stream decoder XXX. + * \{ + */ + + /** stream decoder XXX. + */ class Stream { public: class State { @@ -114,12 +145,27 @@ namespace FLAC { void operator=(const Stream &); }; + /* \} */ + + // ============================================================ // // Equivalent: FLAC__SeekableStreamDecoder // // ============================================================ + /** \defgroup flacpp_seekable_stream_decoder FLAC++/decoder.h: seekable stream decoder class + * \ingroup flacpp_decoder + * + * \brief + * Brief XXX. + * + * Detailed seekable stream decoder XXX. + * \{ + */ + + /** seekable stream decoder XXX. + */ class SeekableStream { public: class State { @@ -192,12 +238,27 @@ namespace FLAC { void operator=(const SeekableStream &); }; + /* \} */ + + // ============================================================ // // Equivalent: FLAC__FileDecoder // // ============================================================ + /** \defgroup flacpp_file_decoder FLAC++/decoder.h: file decoder class + * \ingroup flacpp_decoder + * + * \brief + * Brief XXX. + * + * Detailed file decoder XXX. + * \{ + */ + + /** file decoder XXX. + */ class File { public: class State { @@ -258,6 +319,8 @@ namespace FLAC { void operator=(const File &); }; + /* \} */ + }; }; diff --git a/include/FLAC++/encoder.h b/include/FLAC++/encoder.h index dca7d4cc..7166e289 100644 --- a/include/FLAC++/encoder.h +++ b/include/FLAC++/encoder.h @@ -30,6 +30,25 @@ // =============================================================== +/** \file include/FLAC++/encoder.h + * + * \brief + * This module contains the classes which implement the various + * encoders. + * + * See the detailed documentation in the + * \link flacpp_encoder encoder \endlink module. + */ + +/** \defgroup flacpp_encoder FLAC++/encoder.h: encoder classes + * \ingroup flacpp + * + * \brief + * Brief XXX. + * + * Detailed encoder XXX. + */ + namespace FLAC { namespace Encoder { @@ -47,6 +66,18 @@ namespace FLAC { // // ============================================================ + /** \defgroup flacpp_stream_encoder FLAC++/encoder.h: stream encoder class + * \ingroup flacpp_encoder + * + * \brief + * Brief XXX. + * + * Detailed stream encoder XXX. + * \{ + */ + + /** stream encoder XXX. + */ class Stream { public: class State { @@ -122,6 +153,8 @@ namespace FLAC { void operator=(const Stream &); }; + /* \} */ + }; }; diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h index d08c8129..f9d7325a 100644 --- a/include/FLAC++/metadata.h +++ b/include/FLAC++/metadata.h @@ -29,6 +29,30 @@ // // =============================================================== +/** \file include/FLAC++/metadata.h + * + * \brief + * This module provides classes for creating and manipulating FLAC + * metadata blocks in memory, and three progressively more powerful + * interfaces for traversing and editing metadata in FLAC files. + * + * See the detailed documentation for each interface in the + * \link flacpp_metadata metadata \endlink module. + */ + +/** \defgroup flacpp_metadata FLAC++/metadata.h: metadata interfaces + * \ingroup flacpp + * + * \brief + * This module provides classes for creating and manipulating FLAC + * metadata blocks in memory, and three progressively more powerful + * interfaces for traversing and editing metadata in FLAC files. + * + * The behavior closely mimics the C layer interface; be sure to read + * the detailed description of the + * \link flac_metadata C metadata module \endlink. + */ + namespace FLAC { namespace Metadata { @@ -39,77 +63,129 @@ namespace FLAC { // // ============================================================ - class Prototype; + /** \defgroup flacpp_metadata_object FLAC++/metadata.h: metadata object classes + * \ingroup flacpp_metadata + * + * This module contains classes representing FLAC metadata + * blocks in memory. + * + * The behavior closely mimics the C layer interface; be + * sure to read the detailed description of the + * \link flac_metadata_object C metadata object module \endlink. + * + * Any time a metadata object is constructed or assigned, you + * should check is_valid() to make sure the underlying + * ::FLAC__StreamMetadata object was able to be created. + * + * \warning + * When the get_*() methods of any metadata object method + * return you a const pointer, DO NOT disobey and write into it. + * Always use the set_*() methods. + * + * \{ + */ - Prototype *clone(const Prototype *); - - // NOTE: When the get_*() methods return you a const pointer, - // DO NOT disobey and write into it. Always use the set_*() - // methods. - - //! - //! \class Prototype metadata.h FLAC++/metadata.h - //! \brief Base class for all metadata block types. - //! + /** Base class for all metadata block types. + */ class Prototype { protected: - //! - //! Constructs a copy of the given object. This form - //! always performs a deep copy. - //! - Prototype(const Prototype &object); + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + Prototype(const Prototype &); + Prototype(const ::FLAC__StreamMetadata &); + Prototype(const ::FLAC__StreamMetadata *); + //@} - //! - //! Constructs a copy of the given object. This form - //! always performs a deep copy. - //! - Prototype(const ::FLAC__StreamMetadata &object); - - //! - //! Constructs a copy of the given object. This form - //! always performs a deep copy. - //! - Prototype(const ::FLAC__StreamMetadata *object); - - //! - //! Constructs an object with copy control. When 'copy' - //! is true, behaves identically to - //! FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object). - //! When 'copy' is false, the instance takes ownership of - //! the pointer and the ::FLAC__StreamMetadata object will - //! be freed by the destructor. - //! + /** Constructs an object with copy control. When \a copy + * is \c true, behaves identically to + * FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object). + * When \a copy is \c false, the instance takes ownership of + * the pointer and the ::FLAC__StreamMetadata object will + * be freed by the destructor. + * + * \assert + * \code object != NULL \endcode + */ Prototype(::FLAC__StreamMetadata *object, bool copy); + //@{ + /** Assign from another object. Always performs a deep copy. */ void operator=(const Prototype &); - void operator=(const ::FLAC__StreamMetadata &); // this form always copies - void operator=(const ::FLAC__StreamMetadata *); // this form always copies + void operator=(const ::FLAC__StreamMetadata &); + void operator=(const ::FLAC__StreamMetadata *); + //@} + /** Deletes the underlying ::FLAC__StreamMetadata object. + */ virtual void clear(); ::FLAC__StreamMetadata *object_; public: + /** Deletes the underlying ::FLAC__StreamMetadata object. + */ virtual ~Prototype(); + //@{ + /** Check for equality, performing a deep compare by following pointers. */ inline bool operator==(const Prototype &) const; inline bool operator==(const ::FLAC__StreamMetadata &) const; inline bool operator==(const ::FLAC__StreamMetadata *) const; + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ inline bool operator!=(const Prototype &) const; inline bool operator!=(const ::FLAC__StreamMetadata &) const; inline bool operator!=(const ::FLAC__StreamMetadata *) const; + //@} friend class SimpleIterator; friend class Iterator; + /** Returns \c true if the object was correctly constructed + * (i.e. the underlying ::FLAC__StreamMetadata object was + * properly allocated), else \c false. + */ inline bool is_valid() const; + /** Returns \c true if this block is the last block in a + * stream, else \c false. + * + * \assert + * \code is_valid() \endcode + */ bool get_is_last() const; - FLAC__MetadataType get_type() const; - unsigned get_length() const; // NOTE: does not include the header, per spec + /** Returns the type of the block. + * + * \assert + * \code is_valid() \endcode + */ + ::FLAC__MetadataType get_type() const; + + /** Returns the stream length of the metadata block. + * + * \note + * The length does not include the metadata block header, + * per spec. + * + * \assert + * \code is_valid() \endcode + */ + unsigned get_length() const; + + /** Sets the "is_last" flag for the block. When using the iterators + * it is not necessary to set this flag; they will do it for you. + * + * \assert + * \code is_valid() \endcode + */ void set_is_last(bool); private: - Prototype(); // Private and undefined so you can't use it + /** Private and undefined so you can't use it. */ + Prototype(); // These are used only by Iterator bool is_reference_; @@ -137,26 +213,55 @@ namespace FLAC { inline bool Prototype::is_valid() const { return 0 != object_; } + /** Create a deep copy of an object and return it. */ + Prototype *clone(const Prototype *); + + /** STREAMINFO metadata block. + */ class StreamInfo : public Prototype { public: StreamInfo(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ inline StreamInfo(const StreamInfo &object): Prototype(object) { } inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { } inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + * + * \assert + * \code object != NULL \endcode + */ inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + ~StreamInfo(); + //@{ + /** Assign from another object. Always performs a deep copy. */ inline void operator=(const StreamInfo &object) { Prototype::operator=(object); } inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); } inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); } + //@} + //@{ + /** Check for equality, performing a deep compare by following pointers. */ inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); } inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); } inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} unsigned get_min_blocksize() const; unsigned get_max_blocksize() const; @@ -179,6 +284,8 @@ namespace FLAC { void set_md5sum(const FLAC__byte value[16]); }; + /** PADDING block. + */ class Padding : public Prototype { public: Padding(); @@ -202,6 +309,8 @@ namespace FLAC { void set_length(unsigned length); }; + /** APPLICATION block. + */ class Application : public Prototype { public: Application(); @@ -230,6 +339,8 @@ namespace FLAC { bool set_data(FLAC__byte *data, unsigned length, bool copy); }; + /** SEEKTABLE block. + */ class SeekTable : public Prototype { public: SeekTable(); @@ -260,8 +371,12 @@ namespace FLAC { bool is_legal() const; }; + /** VORBIS_COMMENT block. + */ class VorbisComment : public Prototype { public: + /** XXX class VorbisComment::Entry + */ class Entry { public: Entry(); @@ -333,6 +448,8 @@ namespace FLAC { bool delete_comment(unsigned index); }; + /* \} */ + // ============================================================ // @@ -340,8 +457,21 @@ namespace FLAC { // // ============================================================ + /** \defgroup flacpp_metadata_level0 FLAC++/metadata.h: metadata level 0 interface + * \ingroup flacpp_metadata + * + * \brief + * XXX + * + * Detailed XXX. + * + * \{ + */ + bool get_streaminfo(const char *filename, StreamInfo &streaminfo); + /* \} */ + // ============================================================ // @@ -371,8 +501,23 @@ namespace FLAC { // // ============================================================ + /** \defgroup flacpp_metadata_level1 FLAC++/metadata.h: metadata level 1 interface + * \ingroup flacpp_metadata + * + * \brief + * XXX + * + * Detailed XXX. + * + * \{ + */ + + /** XXX class SimpleIterator + */ class SimpleIterator { public: + /** XXX class SimpleIterator::Status + */ class Status { public: inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { } @@ -405,6 +550,8 @@ namespace FLAC { void clear(); }; + /* \} */ + // ============================================================ // @@ -443,8 +590,23 @@ namespace FLAC { // // ============================================================ + /** \defgroup flacpp_metadata_level2 FLAC++/metadata.h: metadata level 2 interface + * \ingroup flacpp_metadata + * + * \brief + * XXX + * + * Detailed XXX. + * + * \{ + */ + + /** XXX class Chain + */ class Chain { public: + /** XXX class Chain::Status + */ class Status { public: inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { } @@ -473,6 +635,8 @@ namespace FLAC { virtual void clear(); }; + /** XXX class Iterator + */ class Iterator { public: Iterator(); @@ -497,7 +661,872 @@ namespace FLAC { virtual void clear(); }; + /* \} */ + }; }; #endif +#if 0 + Prototype *clone(const Prototype *object) + { + FLAC__ASSERT(0 != object); + + const StreamInfo *streaminfo = dynamic_cast(object); + const Padding *padding = dynamic_cast(object); + const Application *application = dynamic_cast(object); + const SeekTable *seektable = dynamic_cast(object); + const VorbisComment *vorbiscomment = dynamic_cast(object); + + if(0 != streaminfo) + return new StreamInfo(*streaminfo); + else if(0 != padding) + return new Padding(*padding); + else if(0 != application) + return new Application(*application); + else if(0 != seektable) + return new SeekTable(*seektable); + else if(0 != vorbiscomment) + return new VorbisComment(*vorbiscomment); + else { + FLAC__ASSERT(0); + return 0; + } + } + + // + // StreamInfo + // + + StreamInfo::StreamInfo(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false) + { } + + StreamInfo::~StreamInfo() + { } + + unsigned StreamInfo::get_min_blocksize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.min_blocksize; + } + + unsigned StreamInfo::get_max_blocksize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.max_blocksize; + } + + unsigned StreamInfo::get_min_framesize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.min_framesize; + } + + unsigned StreamInfo::get_max_framesize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.max_framesize; + } + + unsigned StreamInfo::get_sample_rate() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.sample_rate; + } + + unsigned StreamInfo::get_channels() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.channels; + } + + unsigned StreamInfo::get_bits_per_sample() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.bits_per_sample; + } + + FLAC__uint64 StreamInfo::get_total_samples() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.total_samples; + } + + const FLAC__byte *StreamInfo::get_md5sum() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.md5sum; + } + + void StreamInfo::set_min_blocksize(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE); + FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE); + object_->data.stream_info.min_blocksize = value; + } + + void StreamInfo::set_max_blocksize(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE); + FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE); + object_->data.stream_info.max_blocksize = value; + } + + void StreamInfo::set_min_framesize(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)); + object_->data.stream_info.min_framesize = value; + } + + void StreamInfo::set_max_framesize(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)); + object_->data.stream_info.max_framesize = value; + } + + void StreamInfo::set_sample_rate(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value)); + object_->data.stream_info.sample_rate = value; + } + + void StreamInfo::set_channels(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value > 0); + FLAC__ASSERT(value <= FLAC__MAX_CHANNELS); + object_->data.stream_info.channels = value; + } + + void StreamInfo::set_bits_per_sample(unsigned value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE); + FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE); + object_->data.stream_info.bits_per_sample = value; + } + + void StreamInfo::set_total_samples(FLAC__uint64 value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)); + object_->data.stream_info.total_samples = value; + } + + void StreamInfo::set_md5sum(const FLAC__byte value[16]) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != value); + memcpy(object_->data.stream_info.md5sum, value, 16); + } + + + // + // Padding + // + + Padding::Padding(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false) + { } + + Padding::~Padding() + { } + + void Padding::set_length(unsigned length) + { + FLAC__ASSERT(is_valid()); + object_->length = length; + } + + + // + // Application + // + + Application::Application(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false) + { } + + Application::~Application() + { } + + const FLAC__byte *Application::get_id() const + { + FLAC__ASSERT(is_valid()); + return object_->data.application.id; + } + + const FLAC__byte *Application::get_data() const + { + FLAC__ASSERT(is_valid()); + return object_->data.application.data; + } + + void Application::set_id(const FLAC__byte value[4]) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != value); + memcpy(object_->data.application.id, value, 4); + } + + bool Application::set_data(const FLAC__byte *data, unsigned length) + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true); + } + + bool Application::set_data(FLAC__byte *data, unsigned length, bool copy) + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy); + } + + + // + // SeekTable + // + + SeekTable::SeekTable(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false) + { } + + SeekTable::~SeekTable() + { } + + unsigned SeekTable::get_num_points() const + { + FLAC__ASSERT(is_valid()); + return object_->data.seek_table.num_points; + } + + ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index < object_->data.seek_table.num_points); + return object_->data.seek_table.points[index]; + } + + void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index < object_->data.seek_table.num_points); + ::FLAC__metadata_object_seektable_set_point(object_, index, point); + } + + bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index <= object_->data.seek_table.num_points); + return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point); + } + + bool SeekTable::delete_point(unsigned index) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index < object_->data.seek_table.num_points); + return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index); + } + + bool SeekTable::is_legal() const + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_object_seektable_is_legal(object_); + } + + + // + // VorbisComment::Entry + // + + VorbisComment::Entry::Entry() + { + zero(); + } + + VorbisComment::Entry::Entry(const char *field, unsigned field_length) + { + zero(); + construct(field, field_length); + } + + VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length) + { + zero(); + construct(field_name, field_value, field_value_length); + } + + VorbisComment::Entry::Entry(const Entry &entry) + { + FLAC__ASSERT(entry.is_valid()); + zero(); + construct((const char *)entry.entry_.entry, entry.entry_.length); + } + + void VorbisComment::Entry::operator=(const Entry &entry) + { + FLAC__ASSERT(entry.is_valid()); + clear(); + construct((const char *)entry.entry_.entry, entry.entry_.length); + } + + VorbisComment::Entry::~Entry() + { + clear(); + } + + bool VorbisComment::Entry::is_valid() const + { + return is_valid_; + } + + unsigned VorbisComment::Entry::get_field_length() const + { + FLAC__ASSERT(is_valid()); + return entry_.length; + } + + unsigned VorbisComment::Entry::get_field_name_length() const + { + FLAC__ASSERT(is_valid()); + return field_name_length_; + } + + unsigned VorbisComment::Entry::get_field_value_length() const + { + FLAC__ASSERT(is_valid()); + return field_value_length_; + } + + ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const + { + FLAC__ASSERT(is_valid()); + return entry_; + } + + const char *VorbisComment::Entry::get_field() const + { + FLAC__ASSERT(is_valid()); + return (const char *)entry_.entry; + } + + const char *VorbisComment::Entry::get_field_name() const + { + FLAC__ASSERT(is_valid()); + return field_name_; + } + + const char *VorbisComment::Entry::get_field_value() const + { + FLAC__ASSERT(is_valid()); + return field_value_; + } + + bool VorbisComment::Entry::set_field(const char *field, unsigned field_length) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != field); + + clear_entry(); + + if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length))) { + is_valid_ = false; + } + else { + entry_.length = field_length; + memcpy(entry_.entry, field, field_length); + (void) parse_field(); + } + + return is_valid_; + } + + bool VorbisComment::Entry::set_field_name(const char *field_name) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != field_name); + + clear_field_name(); + + if(0 == (field_name_ = strdup(field_name))) { + is_valid_ = false; + } + else { + field_name_length_ = strlen(field_name_); + compose_field(); + } + + return is_valid_; + } + + bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != field_value); + + clear_field_value(); + + if(0 == (field_value_ = (char *)malloc(field_value_length))) { + is_valid_ = false; + } + else { + field_value_length_ = field_value_length; + memcpy(field_value_, field_value, field_value_length); + compose_field(); + } + + return is_valid_; + } + + void VorbisComment::Entry::zero() + { + is_valid_ = true; + entry_.length = 0; + entry_.entry = 0; + field_name_ = 0; + field_name_length_ = 0; + field_value_ = 0; + field_value_length_ = 0; + } + + void VorbisComment::Entry::clear() + { + clear_entry(); + clear_field_name(); + clear_field_value(); + is_valid_ = true; + } + + void VorbisComment::Entry::clear_entry() + { + if(0 != entry_.entry) { + free(entry_.entry); + entry_.entry = 0; + entry_.length = 0; + } + } + + void VorbisComment::Entry::clear_field_name() + { + if(0 != field_name_) { + free(field_name_); + field_name_ = 0; + field_name_length_ = 0; + } + } + + void VorbisComment::Entry::clear_field_value() + { + if(0 != field_value_) { + free(field_value_); + field_value_ = 0; + field_value_length_ = 0; + } + } + + void VorbisComment::Entry::construct(const char *field, unsigned field_length) + { + if(set_field(field, field_length)) + parse_field(); + } + + void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length) + { + if(set_field_name(field_name) && set_field_value(field_value, field_value_length)) + compose_field(); + } + + void VorbisComment::Entry::compose_field() + { + clear_entry(); + + if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_))) { + is_valid_ = false; + } + else { + memcpy(entry_.entry, field_name_, field_name_length_); + entry_.length += field_name_length_; + memcpy(entry_.entry + entry_.length, "=", 1); + entry_.length += 1; + memcpy(entry_.entry + entry_.length, field_value_, field_value_length_); + entry_.length += field_value_length_; + is_valid_ = true; + } + } + + void VorbisComment::Entry::parse_field() + { + clear_field_name(); + clear_field_value(); + + const char *p = (const char *)memchr(entry_.entry, '=', entry_.length); + + if(0 == p) + p = (const char *)entry_.entry + entry_.length; + + field_name_length_ = p - (const char *)entry_.entry; + if(0 == (field_name_ = (char *)malloc(field_name_length_ + 1))) { // +1 for the trailing \0 + is_valid_ = false; + return; + } + memcpy(field_name_, entry_.entry, field_name_length_); + field_name_[field_name_length_] = '\0'; + + if(entry_.length - field_name_length_ == 0) { + field_value_length_ = 0; + if(0 == (field_value_ = (char *)malloc(0))) { + is_valid_ = false; + return; + } + } + else { + field_value_length_ = entry_.length - field_name_length_ - 1; + if(0 == (field_value_ = (char *)malloc(field_value_length_))) { + is_valid_ = false; + return; + } + memcpy(field_value_, ++p, field_value_length_); + } + + is_valid_ = true; + } + + + // + // VorbisComment + // + + VorbisComment::VorbisComment(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false) + { } + + VorbisComment::~VorbisComment() + { } + + unsigned VorbisComment::get_num_comments() const + { + FLAC__ASSERT(is_valid()); + return object_->data.vorbis_comment.num_comments; + } + + VorbisComment::Entry VorbisComment::get_vendor_string() const + { + FLAC__ASSERT(is_valid()); + return Entry((const char *)object_->data.vorbis_comment.vendor_string.entry, object_->data.vorbis_comment.vendor_string.length); + } + + VorbisComment::Entry VorbisComment::get_comment(unsigned index) const + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments); + return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length); + } + + bool VorbisComment::set_vendor_string(const VorbisComment::Entry &entry) + { + FLAC__ASSERT(is_valid()); + // vendor_string is a special kind of entry + ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string; + vendor_string.length = entry.get_field_name_length(); + vendor_string.entry = (FLAC__byte*)entry.get_field_name(); // we can cheat on const-ness because we make a copy below: + return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true); + } + + bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments); + return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true); + } + + bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments); + return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true); + } + + bool VorbisComment::delete_comment(unsigned index) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments); + return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index); + } + + + // ============================================================ + // + // Level 0 + // + // ============================================================ + + bool get_streaminfo(const char *filename, StreamInfo &streaminfo) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata s; + + if(::FLAC__metadata_get_streaminfo(filename, &s)) { + streaminfo = s; + return true; + } + else + return false; + } + + + // ============================================================ + // + // Level 1 + // + // ============================================================ + + SimpleIterator::SimpleIterator(): + iterator_(::FLAC__metadata_simple_iterator_new()) + { } + + SimpleIterator::~SimpleIterator() + { + clear(); + } + + void SimpleIterator::clear() + { + if(0 != iterator_) + FLAC__metadata_simple_iterator_delete(iterator_); + iterator_ = 0; + } + + bool SimpleIterator::init(const char *filename, bool preserve_file_stats) + { + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, preserve_file_stats); + } + + bool SimpleIterator::is_valid() const + { + return 0 != iterator_; + } + + SimpleIterator::Status SimpleIterator::status() + { + FLAC__ASSERT(is_valid()); + return Status(::FLAC__metadata_simple_iterator_status(iterator_)); + } + + bool SimpleIterator::is_writable() const + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_); + } + + bool SimpleIterator::next() + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_next(iterator_); + } + + bool SimpleIterator::prev() + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_prev(iterator_); + } + + ::FLAC__MetadataType SimpleIterator::get_block_type() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_simple_iterator_get_block_type(iterator_); + } + + Prototype *SimpleIterator::get_block() + { + FLAC__ASSERT(is_valid()); + return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_)); + } + + bool SimpleIterator::set_block(Prototype *block, bool use_padding) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding); + } + + bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding); + } + + bool SimpleIterator::delete_block(bool use_padding) + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding); + } + + + // ============================================================ + // + // Level 2 + // + // ============================================================ + + Chain::Chain(): + chain_(::FLAC__metadata_chain_new()) + { } + + Chain::~Chain() + { + clear(); + } + + void Chain::clear() + { + if(0 != chain_) + FLAC__metadata_chain_delete(chain_); + chain_ = 0; + } + + bool Chain::is_valid() const + { + return 0 != chain_; + } + + Chain::Status Chain::status() + { + FLAC__ASSERT(is_valid()); + return Status(::FLAC__metadata_chain_status(chain_)); + } + + bool Chain::read(const char *filename) + { + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_chain_read(chain_, filename); + } + + bool Chain::write(bool use_padding, bool preserve_file_stats) + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats); + } + + void Chain::merge_padding() + { + FLAC__ASSERT(is_valid()); + ::FLAC__metadata_chain_merge_padding(chain_); + } + + void Chain::sort_padding() + { + FLAC__ASSERT(is_valid()); + ::FLAC__metadata_chain_sort_padding(chain_); + } + + + Iterator::Iterator(): + iterator_(::FLAC__metadata_iterator_new()) + { } + + Iterator::~Iterator() + { + clear(); + } + + void Iterator::clear() + { + if(0 != iterator_) + FLAC__metadata_iterator_delete(iterator_); + iterator_ = 0; + } + + bool Iterator::is_valid() const + { + return 0 != iterator_; + } + + void Iterator::init(Chain &chain) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(chain.is_valid()); + ::FLAC__metadata_iterator_init(iterator_, chain.chain_); + } + + bool Iterator::next() + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_iterator_next(iterator_); + } + + bool Iterator::prev() + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_iterator_prev(iterator_); + } + + ::FLAC__MetadataType Iterator::get_block_type() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_iterator_get_block_type(iterator_); + } + + Prototype *Iterator::get_block() + { + FLAC__ASSERT(is_valid()); + Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_)); + if(0 != block) + block->set_reference(true); + return block; + } + + bool Iterator::set_block(Prototype *block) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + + bool Iterator::delete_block(bool replace_with_padding) + { + FLAC__ASSERT(is_valid()); + return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding); + } + + bool Iterator::insert_block_before(Prototype *block) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + + bool Iterator::insert_block_after(Prototype *block) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + + }; +}; +#endif diff --git a/include/FLAC/file_decoder.h b/include/FLAC/file_decoder.h index c9d415d9..af7fa943 100644 --- a/include/FLAC/file_decoder.h +++ b/include/FLAC/file_decoder.h @@ -188,7 +188,7 @@ FLAC__FileDecoder *FLAC__file_decoder_new(); * \assert * \code decoder != NULL \endcode */ -void FLAC__file_decoder_delete(FLAC__FileDecoder *); +void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder); /*********************************************************************** diff --git a/include/FLAC/format.h b/include/FLAC/format.h index fae30198..e30a47a1 100644 --- a/include/FLAC/format.h +++ b/include/FLAC/format.h @@ -426,11 +426,22 @@ typedef struct { /** An enumeration of the available metadata block types. */ typedef enum { + FLAC__METADATA_TYPE_STREAMINFO = 0, + /**< STREAMINFO block */ + FLAC__METADATA_TYPE_PADDING = 1, + /**< block */ + FLAC__METADATA_TYPE_APPLICATION = 2, + /**< block */ + FLAC__METADATA_TYPE_SEEKTABLE = 3, - FLAC__METADATA_TYPE_VORBIS_COMMENT = 4 + /**< block */ + + FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, + /**< block */ + } FLAC__MetadataType; /** Maps a FLAC__MetadataType to a C string. @@ -440,6 +451,7 @@ typedef enum { */ extern const char * const FLAC__MetadataTypeString[]; + /** FLAC STREAMINFO structure. (c.f. format specification) */ typedef struct { diff --git a/include/FLAC/stream_decoder.h b/include/FLAC/stream_decoder.h index f43edfee..843ff710 100644 --- a/include/FLAC/stream_decoder.h +++ b/include/FLAC/stream_decoder.h @@ -37,7 +37,7 @@ extern "C" { * \link flac_stream_decoder stream decoder \endlink module. */ -/** \defgroup flac_decoder FLAC/*_decoder.h: decoder interfaces +/** \defgroup flac_decoder FLAC/ *_decoder.h: decoder interfaces * \ingroup flac * * \brief diff --git a/include/FLAC/stream_encoder.h b/include/FLAC/stream_encoder.h index 6380e9a0..8c2fa7ad 100644 --- a/include/FLAC/stream_encoder.h +++ b/include/FLAC/stream_encoder.h @@ -37,7 +37,7 @@ extern "C" { * \link flac_stream_encoder stream encoder \endlink module. */ -/** \defgroup flac_encoder FLAC/*_encoder.h: encoder interfaces +/** \defgroup flac_encoder FLAC/ *_encoder.h: encoder interfaces * \ingroup flac * * \brief @@ -48,11 +48,6 @@ extern "C" { * within a file while encoding seemed like too obscure a feature. */ -/** \defgroup flac_encoder FLAC/*_encoder.h: encoder interfaces - * \ingroup flac - * - */ - /** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface * \ingroup flac_encoder *