From fb74f10df7e6f96764dc6a8b47a4dbe302472560 Mon Sep 17 00:00:00 2001 From: Josh Coalson Date: Wed, 22 May 2002 05:33:29 +0000 Subject: [PATCH] add iterator classes --- include/FLAC++/metadata.h | 215 +++++++++++++++++++++++- src/libFLAC++/metadata.cc | 335 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 549 insertions(+), 1 deletion(-) diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h index 933cf943..74b5ce01 100644 --- a/include/FLAC++/metadata.h +++ b/include/FLAC++/metadata.h @@ -22,11 +22,25 @@ #include "FLAC/metadata.h" +// =============================================================== +// +// Full documentation for the metadata interface can be found +// in the C layer in include/FLAC/metadata.h +// +// =============================================================== + + namespace FLAC { namespace Metadata { + // ============================================================ + // + // Metadata objects + // + // ============================================================ + // NOTE: When the get_*() methods return you a const pointer, - // absolutely DO NOT write into it. Always use the set_*() + // DO NOT disobey and write into it. Always use the set_*() // methods. // base class for all metadata blocks @@ -35,14 +49,29 @@ namespace FLAC { Prototype(::FLAC__StreamMetaData *object, bool copy); virtual ~Prototype(); + void operator=(const Prototype &); + void operator=(const ::FLAC__StreamMetaData &); + void operator=(const ::FLAC__StreamMetaData *); + + virtual void clear(); + ::FLAC__StreamMetaData *object_; public: + friend class SimpleIterator; + friend class Iterator; + inline bool is_valid() const { return 0 != object_; } inline operator bool() const { return is_valid(); } bool get_is_last() const; FLAC__MetaDataType get_type() const; unsigned get_length() const; // NOTE: does not include the header, per spec + private: + Prototype(); // Private and undefined so use can't use it + + // These are used only by Iterator + bool is_reference_; + inline void set_reference(bool x) { is_reference_ = x; } }; class StreamInfo : public Prototype { @@ -51,6 +80,10 @@ namespace FLAC { StreamInfo(::FLAC__StreamMetaData *object, bool copy = false); ~StreamInfo(); + 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); } + unsigned get_min_blocksize() const; unsigned get_max_blocksize() const; unsigned get_min_framesize() const; @@ -77,6 +110,10 @@ namespace FLAC { Padding(); Padding(::FLAC__StreamMetaData *object, bool copy = false); ~Padding(); + + inline void operator=(const Padding &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); } }; class Application : public Prototype { @@ -85,6 +122,10 @@ namespace FLAC { Application(::FLAC__StreamMetaData *object, bool copy = false); ~Application(); + inline void operator=(const Application &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); } + const FLAC__byte *get_id() const; const FLAC__byte *get_data() const; @@ -97,6 +138,10 @@ namespace FLAC { SeekTable(); SeekTable(::FLAC__StreamMetaData *object, bool copy = false); ~SeekTable(); + + inline void operator=(const SeekTable &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); } }; class VorbisComment : public Prototype { @@ -104,6 +149,174 @@ namespace FLAC { VorbisComment(); VorbisComment(::FLAC__StreamMetaData *object, bool copy = false); ~VorbisComment(); + + inline void operator=(const VorbisComment &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); } + inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); } + }; + + // ============================================================ + // + // Level 0 + // + // ============================================================ + + bool get_streaminfo(const char *filename, StreamInfo &streaminfo); + + // ============================================================ + // + // Level 1 + // + // ---------------------------------------------------------- + // + // The flow through the iterator in the C++ layer is similar + // to the C layer: + // + // * Create a SimpleIterator instance + // * Check SimpleIterator::is_valid() + // * Call SimpleIterator::init() and check the return + // * Traverse and/or edit. Edits are written to file + // immediately. + // * Destroy the SimpleIterator instance + // + // ---------------------------------------------------------- + // + // The ownership of pointers in the C++ layer follows that in + // the C layer, i.e. + // * The objects returned by get_block() are yours to + // modify, but changes are not reflected in the FLAC file + // until you call set_block(). The objects are also + // yours to delete; they are not automatically deleted + // when passed to set_block() or insert_block_after(). + // + // ============================================================ + + class SimpleIterator { + public: + class Status { + public: + inline Status(::FLAC__MetaData_SimpleIteratorStatus status): status_(status) { } + inline operator ::FLAC__MetaData_SimpleIteratorStatus() const { return status_; } + inline const char *as_cstring() const { return ::FLAC__MetaData_SimpleIteratorStatusString[status_]; } + protected: + ::FLAC__MetaData_SimpleIteratorStatus status_; + }; + + SimpleIterator(); + virtual ~SimpleIterator(); + + bool init(const char *filename, bool preserve_file_stats = false); + + bool is_valid() const; + inline operator bool() const { return is_valid(); } + Status status(); + bool is_writable() const; + + bool next(); + bool prev(); + + ::FLAC__MetaDataType get_block_type() const; + Prototype *get_block(); + bool set_block(Prototype *block, bool use_padding = true); + bool insert_block_after(Prototype *block, bool use_padding = true); + bool delete_block(bool use_padding = true); + + protected: + ::FLAC__MetaData_SimpleIterator *iterator_; + void clear(); + }; + + // ============================================================ + // + // Level 2 + // + // ---------------------------------------------------------- + // + // The flow through the iterator in the C++ layer is similar + // to the C layer: + // + // * Create a Chain instance + // * Check Chain::is_valid() + // * Call Chain::read() and check the return + // * Traverse and/or edit with an Iterator or with + // Chain::merge_padding() or Chain::sort_padding() + // * Write changes back to FLAC file with Chain::write() + // * Destroy the Chain instance + // + // ---------------------------------------------------------- + // + // The ownership of pointers in the C++ layer follows that in + // the C layer, i.e. + // * The objects returned by Iterator::get_block() are + // owned by the iterator and should not be deleted. + // When you modify the block, you are directly editing + // what's in the chain and do not need to call + // Iterator::set_block(). However the changes will not + // be reflected in the FLAC file until the chain is + // written with Chain::write(). + // + // * When you pass an object to Iterator::set_block(), + // Iterator::insert_block_before(), or + // Iterator::insert_block_after(), the iterator takes + // ownership of the block and it will be deleted with the + // chain. + // + // ============================================================ + + class Chain { + public: + class Status { + public: + inline Status(::FLAC__MetaData_ChainStatus status): status_(status) { } + inline operator ::FLAC__MetaData_ChainStatus() const { return status_; } + inline const char *as_cstring() const { return ::FLAC__MetaData_ChainStatusString[status_]; } + protected: + ::FLAC__MetaData_ChainStatus status_; + }; + + Chain(); + virtual ~Chain(); + + friend class Iterator; + + bool is_valid() const; + inline operator bool() const { return is_valid(); } + Status status(); + + bool read(const char *filename); + bool write(bool use_padding = true, bool preserve_file_stats = false); + + void merge_padding(); + void sort_padding(); + + protected: + ::FLAC__MetaData_Chain *chain_; + virtual void clear(); + }; + + class Iterator { + public: + Iterator(); + virtual ~Iterator(); + + bool is_valid() const; + inline operator bool() const { return is_valid(); } + + void init(Chain *chain); + + bool next(); + bool prev(); + + ::FLAC__MetaDataType get_block_type() const; + Prototype *get_block(); + bool set_block(Prototype *block); + bool delete_block(bool replace_with_padding); + bool insert_block_before(Prototype *block); + bool insert_block_after(Prototype *block); + + protected: + ::FLAC__MetaData_Iterator *iterator_; + virtual void clear(); }; }; diff --git a/src/libFLAC++/metadata.cc b/src/libFLAC++/metadata.cc index 40868944..8939d7f8 100644 --- a/src/libFLAC++/metadata.cc +++ b/src/libFLAC++/metadata.cc @@ -24,6 +24,38 @@ namespace FLAC { namespace Metadata { + // local utility routines + + namespace local { + + Prototype *construct_block(::FLAC__StreamMetaData *object) + { + Prototype *ret = 0; + switch(object->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + ret = new StreamInfo(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_PADDING: + ret = new Padding(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_APPLICATION: + ret = new Application(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + ret = new SeekTable(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + ret = new VorbisComment(object, /*copy=*/false); + break; + default: + FLAC__ASSERT(0); + break; + } + return ret; + } + + }; + // // Prototype // @@ -31,13 +63,46 @@ namespace FLAC { Prototype::Prototype(::FLAC__StreamMetaData *object, bool copy) { FLAC__ASSERT(0 != object); + clear(); object_ = copy? ::FLAC__metadata_object_copy(object) : object; + is_reference_ = false; } Prototype::~Prototype() + { + clear(); + } + + void Prototype::clear() { if(0 != object_) FLAC__metadata_object_delete(object_); + object_ = 0; + } + + void Prototype::operator=(const Prototype &object) + { + clear(); + is_reference_ = object.is_reference_; + if(is_reference_) + object_ = object.object_; + else + object_ = ::FLAC__metadata_object_copy(object.object_); + } + + void Prototype::operator=(const ::FLAC__StreamMetaData &object) + { + clear(); + is_reference_ = false; + object_ = ::FLAC__metadata_object_copy(&object); + } + + void Prototype::operator=(const ::FLAC__StreamMetaData *object) + { + FLAC__ASSERT(0 != object); + clear(); + is_reference_ = false; + object_ = ::FLAC__metadata_object_copy(object); } bool Prototype::get_is_last() const @@ -279,5 +344,275 @@ namespace FLAC { VorbisComment::~VorbisComment() { } + + // ============================================================ + // + // Level 0 + // + // ============================================================ + + bool get_streaminfo(const char *filename, StreamInfo &streaminfo) + { + FLAC__ASSERT(0 != filename); + + FLAC__StreamMetaData s; + + if(FLAC__metadata_get_streaminfo(filename, &s.data.stream_info)) { + 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 ::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 ::FLAC__metadata_simple_iterator_is_writable(iterator_); + } + + bool SimpleIterator::next() + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_simple_iterator_next(iterator_); + } + + bool SimpleIterator::prev() + { + FLAC__ASSERT(is_valid()); + return ::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 ::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 ::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding); + } + + bool SimpleIterator::delete_block(bool use_padding) + { + FLAC__ASSERT(is_valid()); + return ::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 ::FLAC__metadata_chain_read(chain_, filename); + } + + bool Chain::write(bool use_padding, bool preserve_file_stats) + { + FLAC__ASSERT(is_valid()); + return ::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(0 != 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 ::FLAC__metadata_iterator_next(iterator_); + } + + bool Iterator::prev() + { + FLAC__ASSERT(is_valid()); + return ::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 = ::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 ::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 = ::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 = ::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + }; };