Additional manual formatting to taglib sources

This commit is contained in:
Jonas Kvinge
2020-06-14 17:01:05 +02:00
parent 577b7d8ec8
commit ef34dce4dc
217 changed files with 7367 additions and 8204 deletions

View File

@@ -1,5 +1,6 @@
include(CheckLibraryExists) include(CheckLibraryExists)
include(CheckTypeSize) include(CheckTypeSize)
include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles) include(CheckCXXSourceCompiles)
# Check if the size of numeric types are suitable. # Check if the size of numeric types are suitable.

View File

@@ -56,10 +56,10 @@ class APE::File::FilePrivate {
FilePrivate() : APELocation(-1), FilePrivate() : APELocation(-1),
APESize(0), APESize(0),
ID3v1Location(-1), ID3v1Location(-1),
ID3v2Header(0), ID3v2Header(nullptr),
ID3v2Location(-1), ID3v2Location(-1),
ID3v2Size(0), ID3v2Size(0),
properties(0) {} properties(nullptr) {}
~FilePrivate() { ~FilePrivate() {
delete ID3v2Header; delete ID3v2Header;
@@ -98,16 +98,18 @@ bool APE::File::isSupported(IOStream *) {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
APE::File::~File() { APE::File::~File() {
@@ -127,10 +129,12 @@ void APE::File::removeUnsupportedProperties(const StringList &properties) {
} }
PropertyMap APE::File::setProperties(const PropertyMap &properties) { PropertyMap APE::File::setProperties(const PropertyMap &properties) {
if (ID3v1Tag()) if (ID3v1Tag())
ID3v1Tag()->setProperties(properties); ID3v1Tag()->setProperties(properties);
return APETag(true)->setProperties(properties); return APETag(true)->setProperties(properties);
} }
APE::Properties *APE::File::audioProperties() const { APE::Properties *APE::File::audioProperties() const {
@@ -138,6 +142,7 @@ APE::Properties *APE::File::audioProperties() const {
} }
bool APE::File::save() { bool APE::File::save() {
if (readOnly()) { if (readOnly()) {
debug("APE::File::save() -- File is read only."); debug("APE::File::save() -- File is read only.");
return false; return false;
@@ -206,6 +211,7 @@ bool APE::File::save() {
} }
return true; return true;
} }
ID3v1::Tag *APE::File::ID3v1Tag(bool create) { ID3v1::Tag *APE::File::ID3v1Tag(bool create) {
@@ -217,14 +223,16 @@ APE::Tag *APE::File::APETag(bool create) {
} }
void APE::File::strip(int tags) { void APE::File::strip(int tags) {
if (tags & ID3v1) if (tags & ID3v1)
d->tag.set(ApeID3v1Index, 0); d->tag.set(ApeID3v1Index, nullptr);
if (tags & APE) if (tags & APE)
d->tag.set(ApeAPEIndex, 0); d->tag.set(ApeAPEIndex, nullptr);
if (!ID3v1Tag()) if (!ID3v1Tag())
APETag(true); APETag(true);
} }
bool APE::File::hasAPETag() const { bool APE::File::hasAPETag() const {
@@ -240,6 +248,7 @@ bool APE::File::hasID3v1Tag() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void APE::File::read(bool readProperties) { void APE::File::read(bool readProperties) {
// Look for an ID3v2 tag // Look for an ID3v2 tag
d->ID3v2Location = Utils::findID3v2(this); d->ID3v2Location = Utils::findID3v2(this);
@@ -293,4 +302,5 @@ void APE::File::read(bool readProperties) {
d->properties = new Properties(this, streamLength); d->properties = new Properties(this, streamLength);
} }
} }

View File

@@ -53,29 +53,28 @@ class Tag;
//! An implementation of APE metadata //! An implementation of APE metadata
/*! /*!
* This is implementation of APE metadata. * This is implementation of APE metadata.
* *
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream properties from the file.
* properties from the file. *
*/ */
namespace APE { namespace APE {
//! An implementation of TagLib::File with APE specific methods //! An implementation of TagLib::File with APE specific methods
/*! /*!
* This implements and provides an interface for APE files to the * This implements and provides an interface for APE files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional * the abstract TagLib::File API as well as providing some additional information specific to APE files.
* information specific to APE files. *
*/ */
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* This set of flags is used for various operations and is suitable for * This set of flags is used for various operations and is suitable for being OR-ed together.
* being OR-ed together. */
*/
enum TagTypes { enum TagTypes {
//! Empty set. Matches no tag types. //! Empty set. Matches no tag types.
NoTags = 0x0000, NoTags = 0x0000,
@@ -88,140 +87,128 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
}; };
/*! /*!
* Constructs an APE file from \a file. If \a readProperties is true the * Constructs an APE file from \a file.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * \note In the current implementation, \a propertiesStyle is ignored.
*/ */
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average); Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs an APE file from \a stream. If \a readProperties is true the * Constructs an APE file from \a stream.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note TagLib will *not* take ownership of the stream, the caller is * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
* responsible for deleting it after the File object. *
* * \note In the current implementation, \a propertiesStyle is ignored.
* \note In the current implementation, \a propertiesStyle is ignored. */
*/
File(IOStream *stream, bool readProperties = true, File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average); Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
/*! /*!
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag * Returns the Tag for this file. This will be an APE tag, an ID3v1 tag or a combination of the two.
* or a combination of the two. */
*/
virtual Strawberry_TagLib::TagLib::Tag *tag() const; virtual Strawberry_TagLib::TagLib::Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* If the file contains both an APE and an ID3v1 tag, only APE * If the file contains both an APE and an ID3v1 tag, only APE will be converted to the PropertyMap.
* will be converted to the PropertyMap. */
*/
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Removes unsupported properties. Forwards to the actual Tag's * Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
* removeUnsupportedProperties() function. */
*/
void removeUnsupportedProperties(const StringList &properties); void removeUnsupportedProperties(const StringList &properties);
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* Creates an APEv2 tag if necessary. A potentially existing ID3v1 * Creates an APEv2 tag if necessary.
* tag will be updated as well. * A potentially existing ID3v1 tag will be updated as well.
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the APE::Properties for this file. If no audio properties * Returns the APE::Properties for this file.
* were read then this will return a null pointer. * If no audio properties were read then this will return a null pointer.
*/ */
virtual Properties *audioProperties() const; virtual Properties *audioProperties() const;
/*! /*!
* Saves the file. * Saves the file.
* *
* \note According to the official Monkey's Audio SDK, an APE file * \note According to the official Monkey's Audio SDK, an APE file
* can only have either ID3V1 or APE tags, so a parameter is used here. * can only have either ID3V1 or APE tags, so a parameter is used here.
*/ */
virtual bool save(); virtual bool save();
/*! /*!
* Returns a pointer to the ID3v1 tag of the file. * Returns a pointer to the ID3v1 tag of the file.
* *
* If \a create is false (the default) this may return a null pointer * If \a create is false (the default) this may return a null pointer if there is no valid ID3v1 tag.
* if there is no valid ID3v1 tag. If \a create is true it will create * If \a create is true it will create an ID3v1 tag if one does not exist and returns a valid pointer.
* an ID3v1 tag if one does not exist and returns a valid pointer. *
* * \note This may return a valid pointer regardless of whether or not the file on disk has an ID3v1 tag.
* \note This may return a valid pointer regardless of whether or not the * Use hasID3v1Tag() to check if the file on disk actually has an ID3v1 tag.
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file *
* on disk actually has an ID3v1 tag. * \note The Tag <b>is still</b> owned by the MPEG::File and should not be deleted by the user.
* * It will be deleted when the file (object) is destroyed.
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be *
* deleted by the user. It will be deleted when the file (object) is * \see hasID3v1Tag()
* destroyed. */
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false); ID3v1::Tag *ID3v1Tag(bool create = false);
/*! /*!
* Returns a pointer to the APE tag of the file. * Returns a pointer to the APE tag of the file.
* *
* If \a create is false (the default) this may return a null pointer * If \a create is false (the default) this may return a null pointer if there is no valid APE tag.
* if there is no valid APE tag. If \a create is true it will create * If \a create is true it will create an APE tag if one does not exist and returns a valid pointer.
* an APE tag if one does not exist and returns a valid pointer. *
* * \note This may return a valid pointer regardless of whether or not the file on disk has an APE tag.
* \note This may return a valid pointer regardless of whether or not the * Use hasAPETag() to check if the file on disk actually has an APE tag.
* file on disk has an APE tag. Use hasAPETag() to check if the file *
* on disk actually has an APE tag. * \note The Tag <b>is still</b> owned by the MPEG::File and should not be deleted by the user.
* * It will be deleted when the file (object) is destroyed.
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be *
* deleted by the user. It will be deleted when the file (object) is * \see hasAPETag()
* destroyed. */
*
* \see hasAPETag()
*/
APE::Tag *APETag(bool create = false); APE::Tag *APETag(bool create = false);
/*! /*!
* This will remove the tags that match the OR-ed together TagTypes from the * This will remove the tags that match the OR-ed together TagTypes from the file.
* file. By default it removes all tags. * By default it removes all tags.
* *
* \note This will also invalidate pointers to the tags * \note This will also invalidate pointers to the tags as their memory will be freed.
* as their memory will be freed. * \note In order to make the removal permanent save() still needs to be called
* \note In order to make the removal permanent save() still needs to be called */
*/
void strip(int tags = AllTags); void strip(int tags = AllTags);
/*! /*!
* Returns whether or not the file on disk actually has an APE tag. * Returns whether or not the file on disk actually has an APE tag.
* *
* \see APETag() * \see APETag()
*/ */
bool hasAPETag() const; bool hasAPETag() const;
/*! /*!
* Returns whether or not the file on disk actually has an ID3v1 tag. * Returns whether or not the file on disk actually has an ID3v1 tag.
* *
* \see ID3v1Tag() * \see ID3v1Tag()
*/ */
bool hasID3v1Tag() const; bool hasID3v1Tag() const;
/*! /*!
* Returns whether or not the given \a stream can be opened as an APE * Returns whether or not the given \a stream can be opened as an APE file.
* file. *
* * \note This method is designed to do a quick check.
* \note This method is designed to do a quick check. The result may * The result may not necessarily be correct.
* not necessarily be correct. */
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
private: private:

View File

@@ -134,10 +134,12 @@ ByteVector APE::Footer::renderFooter() const {
} }
ByteVector APE::Footer::renderHeader() const { ByteVector APE::Footer::renderHeader() const {
if (!d->headerPresent) if (!d->headerPresent)
return ByteVector(); return ByteVector();
else else
return render(true); return render(true);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -145,6 +147,7 @@ ByteVector APE::Footer::renderHeader() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void APE::Footer::parse(const ByteVector &data) { void APE::Footer::parse(const ByteVector &data) {
if (data.size() < size()) if (data.size() < size())
return; return;
@@ -169,9 +172,11 @@ void APE::Footer::parse(const ByteVector &data) {
d->headerPresent = flags[31]; d->headerPresent = flags[31];
d->footerPresent = !flags[30]; d->footerPresent = !flags[30];
d->isHeader = flags[29]; d->isHeader = flags[29];
} }
ByteVector APE::Footer::render(bool isHeader) const { ByteVector APE::Footer::render(bool isHeader) const {
ByteVector v; ByteVector v;
// add the file identifier -- "APETAGEX" // add the file identifier -- "APETAGEX"
@@ -206,4 +211,5 @@ ByteVector APE::Footer::render(bool isHeader) const {
v.append(ByteVector::fromLongLong(0)); v.append(ByteVector::fromLongLong(0));
return v; return v;
} }

View File

@@ -37,126 +37,127 @@ namespace APE {
//! An implementation of APE footers //! An implementation of APE footers
/*! /*!
* This class implements APE footers (and headers). It attempts to follow, both * This class implements APE footers (and headers).
* semantically and programmatically, the structure specified in * It attempts to follow, both semantically and programmatically,
* the APE v2.0 standard. The API is based on the properties of APE footer and * the structure specified in the APE v2.0 standard.
* headers specified there. * The API is based on the properties of APE footer and headers specified there.
*/ *
*/
class TAGLIB_EXPORT Footer { class TAGLIB_EXPORT Footer {
public: public:
/*! /*!
* Constructs an empty APE footer. * Constructs an empty APE footer.
*/ */
Footer(); Footer();
/*! /*!
* Constructs an APE footer based on \a data. parse() is called * Constructs an APE footer based on \a data. parse() is called immediately.
* immediately. */
*/
Footer(const ByteVector &data); Footer(const ByteVector &data);
/*! /*!
* Destroys the footer. * Destroys the footer.
*/ */
virtual ~Footer(); virtual ~Footer();
/*! /*!
* Returns the version number. (Note: This is the 1000 or 2000.) * Returns the version number. (Note: This is the 1000 or 2000.)
*/ */
unsigned int version() const; unsigned int version() const;
/*! /*!
* Returns true if a header is present in the tag. * Returns true if a header is present in the tag.
*/ */
bool headerPresent() const; bool headerPresent() const;
/*! /*!
* Returns true if a footer is present in the tag. * Returns true if a footer is present in the tag.
*/ */
bool footerPresent() const; bool footerPresent() const;
/*! /*!
* Returns true this is actually the header. * Returns true this is actually the header.
*/ */
bool isHeader() const; bool isHeader() const;
/*! /*!
* Sets whether the header should be rendered or not * Sets whether the header should be rendered or not
*/ */
void setHeaderPresent(bool b) const; void setHeaderPresent(bool b) const;
/*! /*!
* Returns the number of items in the tag. * Returns the number of items in the tag.
*/ */
unsigned int itemCount() const; unsigned int itemCount() const;
/*! /*!
* Set the item count to \a s. * Set the item count to \a s.
* \see itemCount() * \see itemCount()
*/ */
void setItemCount(unsigned int s); void setItemCount(unsigned int s);
/*! /*!
* Returns the tag size in bytes. This is the size of the frame content and footer. * Returns the tag size in bytes.
* The size of the \e entire tag will be this plus the header size, if present. * This is the size of the frame content and footer.
* * The size of the \e entire tag will be this plus the header size, if present.
* \see completeTagSize() *
*/ * \see completeTagSize()
*/
unsigned int tagSize() const; unsigned int tagSize() const;
/*! /*!
* Returns the tag size, including if present, the header * Returns the tag size, including if present, the header
* size. * size.
* *
* \see tagSize() * \see tagSize()
*/ */
unsigned int completeTagSize() const; unsigned int completeTagSize() const;
/*! /*!
* Set the tag size to \a s. * Set the tag size to \a s.
* \see tagSize() * \see tagSize()
*/ */
void setTagSize(unsigned int s); void setTagSize(unsigned int s);
/*! /*!
* Returns the size of the footer. Presently this is always 32 bytes. * Returns the size of the footer. Presently this is always 32 bytes.
*/ */
static unsigned int size(); static unsigned int size();
/*! /*!
* Returns the string used to identify an APE tag inside of a file. * Returns the string used to identify an APE tag inside of a file.
* Presently this is always "APETAGEX". * Presently this is always "APETAGEX".
*/ */
static ByteVector fileIdentifier(); static ByteVector fileIdentifier();
/*! /*!
* Sets the data that will be used as the footer. 32 bytes, * Sets the data that will be used as the footer. 32 bytes,
* starting from \a data will be used. * starting from \a data will be used.
*/ */
void setData(const ByteVector &data); void setData(const ByteVector &data);
/*! /*!
* Renders the footer back to binary format. * Renders the footer back to binary format.
*/ */
ByteVector renderFooter() const; ByteVector renderFooter() const;
/*! /*!
* Renders the header corresponding to the footer. If headerPresent is * Renders the header corresponding to the footer.
* set to false, it returns an empty ByteVector. * If headerPresent is set to false, it returns an empty ByteVector.
*/ */
ByteVector renderHeader() const; ByteVector renderHeader() const;
protected: protected:
/*! /*!
* Called by setData() to parse the footer data. It makes this information * Called by setData() to parse the footer data.
* available through the public API. * It makes this information available through the public API.
*/ */
void parse(const ByteVector &data); void parse(const ByteVector &data);
/*! /*!
* Called by renderFooter and renderHeader * Called by renderFooter and renderHeader
*/ */
ByteVector render(bool isHeader) const; ByteVector render(bool isHeader) const;
private: private:

View File

@@ -33,8 +33,7 @@ using namespace APE;
class APE::Item::ItemPrivate { class APE::Item::ItemPrivate {
public: public:
ItemPrivate() : type(Text), ItemPrivate() : type(Text), readOnly(false) {}
readOnly(false) {}
Item::ItemTypes type; Item::ItemTypes type;
String key; String key;
@@ -47,8 +46,7 @@ class APE::Item::ItemPrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
APE::Item::Item() : d(new ItemPrivate()) { APE::Item::Item() : d(new ItemPrivate()) {}
}
APE::Item::Item(const String &key, const String &value) : d(new ItemPrivate()) { APE::Item::Item(const String &key, const String &value) : d(new ItemPrivate()) {
d->key = key; d->key = key;
@@ -61,6 +59,7 @@ APE::Item::Item(const String &key, const StringList &values) : d(new ItemPrivate
} }
APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new ItemPrivate()) { APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new ItemPrivate()) {
d->key = key; d->key = key;
if (binary) { if (binary) {
d->type = Binary; d->type = Binary;
@@ -69,24 +68,28 @@ APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new
else { else {
d->text.append(value); d->text.append(value);
} }
} }
APE::Item::Item(const Item &item) : d(new ItemPrivate(*item.d)) { APE::Item::Item(const Item &item) : d(new ItemPrivate(*item.d)) {}
}
APE::Item::~Item() { APE::Item::~Item() {
delete d; delete d;
} }
Item &APE::Item::operator=(const Item &item) { Item &APE::Item::operator=(const Item &item) {
Item(item).swap(*this); Item(item).swap(*this);
return *this; return *this;
} }
void APE::Item::swap(Item &item) { void APE::Item::swap(Item &item) {
using std::swap; using std::swap;
swap(d, item.d); swap(d, item.d);
} }
void APE::Item::setReadOnly(bool readOnly) { void APE::Item::setReadOnly(bool readOnly) {
@@ -114,14 +117,16 @@ ByteVector APE::Item::binaryData() const {
} }
void APE::Item::setBinaryData(const ByteVector &value) { void APE::Item::setBinaryData(const ByteVector &value) {
d->type = Binary; d->type = Binary;
d->value = value; d->value = value;
d->text.clear(); d->text.clear();
} }
ByteVector APE::Item::value() const { ByteVector APE::Item::value() const {
// This seems incorrect as it won't be actually rendering the value to keep it
// up to date. // This seems incorrect as it won't be actually rendering the value to keep it up to date.
return d->value; return d->value;
} }
@@ -131,30 +136,39 @@ void APE::Item::setKey(const String &key) {
} }
void APE::Item::setValue(const String &value) { void APE::Item::setValue(const String &value) {
d->type = Text; d->type = Text;
d->text = value; d->text = value;
d->value.clear(); d->value.clear();
} }
void APE::Item::setValues(const StringList &value) { void APE::Item::setValues(const StringList &value) {
d->type = Text; d->type = Text;
d->text = value; d->text = value;
d->value.clear(); d->value.clear();
} }
void APE::Item::appendValue(const String &value) { void APE::Item::appendValue(const String &value) {
d->type = Text; d->type = Text;
d->text.append(value); d->text.append(value);
d->value.clear(); d->value.clear();
} }
void APE::Item::appendValues(const StringList &values) { void APE::Item::appendValues(const StringList &values) {
d->type = Text; d->type = Text;
d->text.append(values); d->text.append(values);
d->value.clear(); d->value.clear();
} }
int APE::Item::size() const { int APE::Item::size() const {
int result = 8 + d->key.size() + 1; int result = 8 + d->key.size() + 1;
switch (d->type) { switch (d->type) {
case Text: case Text:
@@ -174,6 +188,7 @@ int APE::Item::size() const {
break; break;
} }
return result; return result;
} }
StringList APE::Item::toStringList() const { StringList APE::Item::toStringList() const {
@@ -185,13 +200,16 @@ StringList APE::Item::values() const {
} }
String APE::Item::toString() const { String APE::Item::toString() const {
if (d->type == Text && !isEmpty()) if (d->type == Text && !isEmpty())
return d->text.front(); return d->text.front();
else else
return String(); return String();
} }
bool APE::Item::isEmpty() const { bool APE::Item::isEmpty() const {
switch (d->type) { switch (d->type) {
case Text: case Text:
if (d->text.isEmpty()) if (d->text.isEmpty())
@@ -205,9 +223,11 @@ bool APE::Item::isEmpty() const {
default: default:
return false; return false;
} }
} }
void APE::Item::parse(const ByteVector &data) { void APE::Item::parse(const ByteVector &data) {
// 11 bytes is the minimum size for an APE item // 11 bytes is the minimum size for an APE item
if (data.size() < 11) { if (data.size() < 11) {
@@ -232,9 +252,11 @@ void APE::Item::parse(const ByteVector &data) {
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8); d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
else else
d->value = value; d->value = value;
} }
ByteVector APE::Item::render() const { ByteVector APE::Item::render() const {
ByteVector data; ByteVector data;
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
ByteVector value; ByteVector value;
@@ -263,4 +285,5 @@ ByteVector APE::Item::render() const {
data.append(value); data.append(value);
return data; return data;
} }

View File

@@ -32,19 +32,18 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace APE { namespace APE {
//! An implementation of APE-items //! An implementation of APE-items
/*! /*!
* This class provides the features of items in the APEv2 standard. * This class provides the features of items in the APEv2 standard.
*/ */
class TAGLIB_EXPORT Item { class TAGLIB_EXPORT Item {
public: public:
/*! /*!
* Enum of types an Item can have. The value of 3 is reserved. * Enum of types an Item can have. The value of 3 is reserved.
*/ */
enum ItemTypes { enum ItemTypes {
//! Item contains text information coded in UTF-8 //! Item contains text information coded in UTF-8
Text = 0, Text = 0,
@@ -54,62 +53,62 @@ class TAGLIB_EXPORT Item {
Locator = 2 Locator = 2
}; };
/*! /*!
* Constructs an empty item. * Constructs an empty item.
*/ */
Item(); Item();
/*! /*!
* Constructs a text item with \a key and \a value. * Constructs a text item with \a key and \a value.
*/ */
// BIC: Remove this, StringList has a constructor from a single string // BIC: Remove this, StringList has a constructor from a single string
Item(const String &key, const String &value); Item(const String &key, const String &value);
/*! /*!
* Constructs a text item with \a key and \a values. * Constructs a text item with \a key and \a values.
*/ */
Item(const String &key, const StringList &values); Item(const String &key, const StringList &values);
/*! /*!
* Constructs an item with \a key and \a value. * Constructs an item with \a key and \a value.
* If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text * If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text
*/ */
Item(const String &key, const ByteVector &value, bool binary); Item(const String &key, const ByteVector &value, bool binary);
/*! /*!
* Construct an item as a copy of \a item. * Construct an item as a copy of \a item.
*/ */
Item(const Item &item); Item(const Item &item);
/*! /*!
* Destroys the item. * Destroys the item.
*/ */
virtual ~Item(); virtual ~Item();
/*! /*!
* Copies the contents of \a item into this item. * Copies the contents of \a item into this item.
*/ */
Item &operator=(const Item &item); Item &operator=(const Item &item);
/*! /*!
* Exchanges the content of this item by the content of \a item. * Exchanges the content of this item by the content of \a item.
*/ */
void swap(Item &item); void swap(Item &item);
/*! /*!
* Returns the key. * Returns the key.
*/ */
String key() const; String key() const;
/*! /*!
* Returns the binary value. * Returns the binary value.
* If the item type is not \a Binary, always returns an empty ByteVector. * If the item type is not \a Binary, always returns an empty ByteVector.
*/ */
ByteVector binaryData() const; ByteVector binaryData() const;
/*! /*!
* Set the binary value to \a value * Set the binary value to \a value
* The item's type will also be set to \a Binary * The item's type will also be set to \a Binary
*/ */
void setBinaryData(const ByteVector &value); void setBinaryData(const ByteVector &value);
#ifndef DO_NOT_DOCUMENT #ifndef DO_NOT_DOCUMENT
@@ -118,97 +117,90 @@ class TAGLIB_EXPORT Item {
#endif #endif
/*! /*!
* Sets the key for the item to \a key. * Sets the key for the item to \a key.
*/ */
void setKey(const String &key); void setKey(const String &key);
/*! /*!
* Sets the text value of the item to \a value and clears any previous contents. * Sets the text value of the item to \a value and clears any previous contents.
* *
* \see toString() * \see toString()
*/ */
void setValue(const String &value); void setValue(const String &value);
/*! /*!
* Sets the text value of the item to the list of values in \a value and clears * Sets the text value of the item to the list of values in \a value and clears any previous contents.
* any previous contents. *
* * \see toStringList()
* \see toStringList() */
*/
void setValues(const StringList &values); void setValues(const StringList &values);
/*! /*!
* Appends \a value to create (or extend) the current list of text values. * Appends \a value to create (or extend) the current list of text values.
* *
* \see toString() * \see toString()
*/ */
void appendValue(const String &value); void appendValue(const String &value);
/*! /*!
* Appends \a values to extend the current list of text values. * Appends \a values to extend the current list of text values.
* *
* \see toStringList() * \see toStringList()
*/ */
void appendValues(const StringList &values); void appendValues(const StringList &values);
/*! /*!
* Returns the size of the full item. * Returns the size of the full item.
*/ */
int size() const; int size() const;
/*! /*!
* Returns the value as a single string. In case of multiple strings, * Returns the value as a single string. In case of multiple strings, the first is returned.
* the first is returned. If the data type is not \a Text, always returns * If the data type is not \a Text, always returns an empty String.
* an empty String. */
*/
String toString() const; String toString() const;
#ifndef DO_NOT_DOCUMENT
/* Remove in next binary incompatible release */
StringList toStringList() const; StringList toStringList() const;
#endif
/*! /*!
* Returns the list of text values. If the data type is not \a Text, always * Returns the list of text values. If the data type is not \a Text, always returns an empty StringList.
* returns an empty StringList. */
*/
StringList values() const; StringList values() const;
/*! /*!
* Render the item to a ByteVector. * Render the item to a ByteVector.
*/ */
ByteVector render() const; ByteVector render() const;
/*! /*!
* Parse the item from the ByteVector \a data. * Parse the item from the ByteVector \a data.
*/ */
void parse(const ByteVector &data); void parse(const ByteVector &data);
/*! /*!
* Set the item to read-only. * Set the item to read-only.
*/ */
void setReadOnly(bool readOnly); void setReadOnly(bool readOnly);
/*! /*!
* Return true if the item is read-only. * Return true if the item is read-only.
*/ */
bool isReadOnly() const; bool isReadOnly() const;
/*! /*!
* Sets the type of the item to \a type. * Sets the type of the item to \a type.
* *
* \see ItemTypes * \see ItemTypes
*/ */
void setType(ItemTypes type); void setType(ItemTypes type);
/*! /*!
* Returns the type of the item. * Returns the type of the item.
*/ */
ItemTypes type() const; ItemTypes type() const;
/*! /*!
* Returns if the item has any real content. * Returns if the item has any real content.
*/ */
bool isEmpty() const; bool isEmpty() const;
private: private:
@@ -216,7 +208,6 @@ class TAGLIB_EXPORT Item {
ItemPrivate *d; ItemPrivate *d;
}; };
} // namespace APE } // namespace APE
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -61,13 +61,7 @@ class APE::Properties::PropertiesPrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
APE::Properties::Properties(File *, ReadStyle style) : AudioProperties(style), APE::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
d(new PropertiesPrivate()) {
debug("APE::Properties::Properties() -- This constructor is no longer used.");
}
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style),
d(new PropertiesPrivate()) {
read(file, streamLength); read(file, streamLength);
} }
@@ -75,10 +69,6 @@ APE::Properties::~Properties() {
delete d; delete d;
} }
int APE::Properties::length() const {
return lengthInSeconds();
}
int APE::Properties::lengthInSeconds() const { int APE::Properties::lengthInSeconds() const {
return d->length / 1000; return d->length / 1000;
} }
@@ -125,6 +115,7 @@ int headerVersion(const ByteVector &header) {
} // namespace } // namespace
void APE::Properties::read(File *file, long streamLength) { void APE::Properties::read(File *file, long streamLength) {
// First, we assume that the file pointer is set at the first descriptor. // First, we assume that the file pointer is set at the first descriptor.
long offset = file->tell(); long offset = file->tell();
int version = headerVersion(file->readBlock(6)); int version = headerVersion(file->readBlock(6));
@@ -153,9 +144,11 @@ void APE::Properties::read(File *file, long streamLength) {
d->length = static_cast<int>(length + 0.5); d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5); d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
} }
} }
void APE::Properties::analyzeCurrent(File *file) { void APE::Properties::analyzeCurrent(File *file) {
// Read the descriptor // Read the descriptor
file->seek(2, File::Current); file->seek(2, File::Current);
const ByteVector descriptor = file->readBlock(44); const ByteVector descriptor = file->readBlock(44);
@@ -188,9 +181,11 @@ void APE::Properties::analyzeCurrent(File *file) {
const unsigned int blocksPerFrame = header.toUInt(4, false); const unsigned int blocksPerFrame = header.toUInt(4, false);
const unsigned int finalFrameBlocks = header.toUInt(8, false); const unsigned int finalFrameBlocks = header.toUInt(8, false);
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks; d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
} }
void APE::Properties::analyzeOld(File *file) { void APE::Properties::analyzeOld(File *file) {
const ByteVector header = file->readBlock(26); const ByteVector header = file->readBlock(26);
if (header.size() < 26) { if (header.size() < 26) {
debug("APE::Properties::analyzeOld() -- MAC header is too short."); debug("APE::Properties::analyzeOld() -- MAC header is too short.");
@@ -228,4 +223,5 @@ void APE::Properties::analyzeOld(File *file) {
} }
d->bitsPerSample = fmt.toShort(26, false); d->bitsPerSample = fmt.toShort(26, false);
} }

View File

@@ -35,7 +35,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace APE { namespace APE {
class File; class File;
@@ -43,86 +42,66 @@ class File;
//! An implementation of audio property reading for APE //! An implementation of audio property reading for APE
/*! /*!
* This reads the data from an APE stream found in the AudioProperties * This reads the data from an APE stream found in the AudioProperties API.
* API. */
*/
class TAGLIB_EXPORT Properties : public AudioProperties { class TAGLIB_EXPORT Properties : public AudioProperties {
public: public:
/*!
* Create an instance of APE::Properties with the data read from the
* APE::File \a file.
*
* \deprecated
*/
TAGLIB_DEPRECATED Properties(File *file, ReadStyle style = Average);
/*! /*!
* Create an instance of APE::Properties with the data read from the * Create an instance of APE::Properties with the data read from the APE::File \a file.
* APE::File \a file. */
*/
Properties(File *file, long streamLength, ReadStyle style = Average); Properties(File *file, long streamLength, ReadStyle style = Average);
/*! /*!
* Destroys this APE::Properties instance. * Destroys this APE::Properties instance.
*/ */
virtual ~Properties(); virtual ~Properties();
/*! /*!
* Returns the length of the file in seconds. The length is rounded down to * Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
* the nearest whole second. *
* * \see lengthInMilliseconds()
* \note This method is just an alias of lengthInSeconds(). */
*
* \deprecated
*/
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual // BIC: make virtual
int lengthInSeconds() const; int lengthInSeconds() const;
/*! /*!
* Returns the length of the file in milliseconds. * Returns the length of the file in milliseconds.
* *
* \see lengthInSeconds() * \see lengthInSeconds()
*/ */
// BIC: make virtual // BIC: make virtual
int lengthInMilliseconds() const; int lengthInMilliseconds() const;
/*! /*!
* Returns the average bit rate of the file in kb/s. * Returns the average bit rate of the file in kb/s.
*/ */
virtual int bitrate() const; virtual int bitrate() const;
/*! /*!
* Returns the sample rate in Hz. * Returns the sample rate in Hz.
*/ */
virtual int sampleRate() const; virtual int sampleRate() const;
/*! /*!
* Returns the number of audio channels. * Returns the number of audio channels.
*/ */
virtual int channels() const; virtual int channels() const;
/*! /*!
* Returns the number of bits per audio sample. * Returns the number of bits per audio sample.
*/ */
int bitsPerSample() const; int bitsPerSample() const;
/*! /*!
* Returns the total number of audio samples in file. * Returns the total number of audio samples in file.
*/ */
unsigned int sampleFrames() const; unsigned int sampleFrames() const;
/*! /*!
* Returns APE version. * Returns APE version.
*/ */
int version() const; int version() const;
private: private:

View File

@@ -51,7 +51,7 @@ const unsigned int MaxKeyLength = 255;
bool isKeyValid(const ByteVector &key) { bool isKeyValid(const ByteVector &key) {
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 }; const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", nullptr };
// only allow printable ASCII including space (32..126) // only allow printable ASCII including space (32..126)
@@ -62,7 +62,7 @@ bool isKeyValid(const ByteVector &key) {
} }
const String upperKey = String(key).upper(); const String upperKey = String(key).upper();
for (size_t i = 0; invalidKeys[i] != 0; ++i) { for (size_t i = 0; invalidKeys[i] != nullptr; ++i) {
if (upperKey == invalidKeys[i]) if (upperKey == invalidKeys[i])
return false; return false;
} }
@@ -73,7 +73,7 @@ bool isKeyValid(const ByteVector &key) {
class APE::Tag::TagPrivate { class APE::Tag::TagPrivate {
public: public:
TagPrivate() : file(0), footerLocation(0) {} TagPrivate() : file(nullptr), footerLocation(0) {}
File *file; File *file;
long footerLocation; long footerLocation;
@@ -207,6 +207,7 @@ const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions
} // namespace } // namespace
PropertyMap APE::Tag::properties() const { PropertyMap APE::Tag::properties() const {
PropertyMap properties; PropertyMap properties;
ItemListMap::ConstIterator it = itemListMap().begin(); ItemListMap::ConstIterator it = itemListMap().begin();
for (; it != itemListMap().end(); ++it) { for (; it != itemListMap().end(); ++it) {
@@ -226,15 +227,19 @@ PropertyMap APE::Tag::properties() const {
} }
} }
return properties; return properties;
} }
void APE::Tag::removeUnsupportedProperties(const StringList &properties) { void APE::Tag::removeUnsupportedProperties(const StringList &properties) {
StringList::ConstIterator it = properties.begin(); StringList::ConstIterator it = properties.begin();
for (; it != properties.end(); ++it) for (; it != properties.end(); ++it)
removeItem(*it); removeItem(*it);
} }
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) { PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) {
PropertyMap properties(origProps); // make a local copy that can be modified PropertyMap properties(origProps); // make a local copy that can be modified
// see comment in properties() // see comment in properties()
@@ -280,10 +285,12 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) {
} }
bool APE::Tag::checkKey(const String &key) { bool APE::Tag::checkKey(const String &key) {
if (key.size() < MinKeyLength || key.size() > MaxKeyLength) if (key.size() < MinKeyLength || key.size() > MaxKeyLength)
return false; return false;
return isKeyValid(key.data(String::UTF8)); return isKeyValid(key.data(String::UTF8));
} }
APE::Footer *APE::Tag::footer() const { APE::Footer *APE::Tag::footer() const {
@@ -299,6 +306,7 @@ void APE::Tag::removeItem(const String &key) {
} }
void APE::Tag::addValue(const String &key, const String &value, bool replace) { void APE::Tag::addValue(const String &key, const String &value, bool replace) {
if (replace) if (replace)
removeItem(key); removeItem(key);
@@ -314,24 +322,29 @@ void APE::Tag::addValue(const String &key, const String &value, bool replace) {
it->second.appendValue(value); it->second.appendValue(value);
else else
setItem(key, Item(key, value)); setItem(key, Item(key, value));
} }
void APE::Tag::setData(const String &key, const ByteVector &value) { void APE::Tag::setData(const String &key, const ByteVector &value) {
removeItem(key); removeItem(key);
if (value.isEmpty()) if (value.isEmpty())
return; return;
setItem(key, Item(key, value, true)); setItem(key, Item(key, value, true));
} }
void APE::Tag::setItem(const String &key, const Item &item) { void APE::Tag::setItem(const String &key, const Item &item) {
if (!checkKey(key)) { if (!checkKey(key)) {
debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key."); debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
return; return;
} }
d->itemListMap[key.upper()] = item; d->itemListMap[key.upper()] = item;
} }
bool APE::Tag::isEmpty() const { bool APE::Tag::isEmpty() const {
@@ -343,6 +356,7 @@ bool APE::Tag::isEmpty() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void APE::Tag::read() { void APE::Tag::read() {
if (d->file && d->file->isValid()) { if (d->file && d->file->isValid()) {
d->file->seek(d->footerLocation); d->file->seek(d->footerLocation);
@@ -355,9 +369,11 @@ void APE::Tag::read() {
d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize()); d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
parse(d->file->readBlock(d->footer.tagSize() - Footer::size())); parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
} }
} }
ByteVector APE::Tag::render() const { ByteVector APE::Tag::render() const {
ByteVector data; ByteVector data;
unsigned int itemCount = 0; unsigned int itemCount = 0;
@@ -371,9 +387,11 @@ ByteVector APE::Tag::render() const {
d->footer.setHeaderPresent(true); d->footer.setHeaderPresent(true);
return d->footer.renderHeader() + data + d->footer.renderFooter(); return d->footer.renderHeader() + data + d->footer.renderFooter();
} }
void APE::Tag::parse(const ByteVector &data) { void APE::Tag::parse(const ByteVector &data) {
// 11 bytes is the minimum size for an APE item // 11 bytes is the minimum size for an APE item
if (data.size() < 11) if (data.size() < 11)
@@ -404,4 +422,5 @@ void APE::Tag::parse(const ByteVector &data) {
pos += keyLength + valLegnth + 9; pos += keyLength + valLegnth + 9;
} }
} }

View File

@@ -46,10 +46,10 @@ namespace APE {
class Footer; class Footer;
/*! /*!
* A mapping between a list of item names, or keys, and the associated item. * A mapping between a list of item names, or keys, and the associated item.
* *
* \see APE::Tag::itemListMap() * \see APE::Tag::itemListMap()
*/ */
typedef Map<const String, Item> ItemListMap; typedef Map<const String, Item> ItemListMap;
@@ -58,31 +58,29 @@ typedef Map<const String, Item> ItemListMap;
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public: public:
/*! /*!
* Create an APE tag with default values. * Create an APE tag with default values.
*/ */
Tag(); Tag();
/*! /*!
* Create an APE tag and parse the data in \a file with APE footer at * Create an APE tag and parse the data in \a file with APE footer at
* \a tagOffset. * \a tagOffset.
*/ */
Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation); Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation);
/*! /*!
* Destroys this Tag instance. * Destroys this Tag instance.
*/ */
virtual ~Tag(); virtual ~Tag();
/*! /*!
* Renders the in memory values to a ByteVector suitable for writing to * Renders the in memory values to a ByteVector suitable for writing to the file.
* the file. */
*/
ByteVector render() const; ByteVector render() const;
/*! /*!
* Returns the string "APETAGEX" suitable for usage in locating the tag in a * Returns the string "APETAGEX" suitable for usage in locating the tag in a file.
* file. */
*/
static ByteVector fileIdentifier(); static ByteVector fileIdentifier();
// Reimplementations. // Reimplementations.
@@ -104,94 +102,91 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
virtual void setTrack(unsigned int i); virtual void setTrack(unsigned int i);
/*! /*!
* Implements the unified tag dictionary interface -- export function. * Implements the unified tag dictionary interface -- export function.
* APE tags are perfectly compatible with the dictionary interface because they * APE tags are perfectly compatible with the dictionary interface because they
* support both arbitrary tag names and multiple values. Currently only * support both arbitrary tag names and multiple values.
* APE items of type *Text* are handled by the dictionary interface; all *Binary* * Currently only APE items of type *Text* are handled by the dictionary interface; all *Binary*
* and *Locator* items will be put into the unsupportedData list and can be * and *Locator* items will be put into the unsupportedData list and can be
* deleted on request using removeUnsupportedProperties(). The same happens * deleted on request using removeUnsupportedProperties().
* to Text items if their key is invalid for PropertyMap (which should actually * The same happens to Text items if their key is invalid for PropertyMap (which should actually never happen).
* never happen). *
* * The only conversion done by this export function is to rename the APE tags
* The only conversion done by this export function is to rename the APE tags * TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST,
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively, * respectively, in order to be compliant with the names used in other formats.
* in order to be compliant with the names used in other formats. */
*/
PropertyMap properties() const; PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties); void removeUnsupportedProperties(const StringList &properties);
/*! /*!
* Implements the unified tag dictionary interface -- import function. The same * Implements the unified tag dictionary interface -- import function.
* comments as for the export function apply; additionally note that the APE tag * The same comments as for the export function apply; additionally note that the APE tag
* specification requires keys to have between 2 and 16 printable ASCII characters * specification requires keys to have between 2 and 16 printable ASCII characters
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+". * with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Check if the given String is a valid APE tag key. * Check if the given String is a valid APE tag key.
*/ */
static bool checkKey(const String &); static bool checkKey(const String &);
/*! /*!
* Returns a pointer to the tag's footer. * Returns a pointer to the tag's footer.
*/ */
Footer *footer() const; Footer *footer() const;
/*! /*!
* Returns a reference to the item list map. This is an ItemListMap of * Returns a reference to the item list map.
* all of the items in the tag. * This is an ItemListMap of all of the items in the tag.
* *
* This is the most powerful structure for accessing the items of the tag. * This is the most powerful structure for accessing the items of the tag.
* *
* APE tags are case-insensitive, all keys in this map have been converted * APE tags are case-insensitive, all keys in this map have been converted
* to upper case. * to upper case.
* *
* \warning You should not modify this data structure directly, instead * \warning You should not modify this data structure directly, instead
* use setItem() and removeItem(). * use setItem() and removeItem().
*/ */
const ItemListMap &itemListMap() const; const ItemListMap &itemListMap() const;
/*! /*!
* Removes the \a key item from the tag * Removes the \a key item from the tag
*/ */
void removeItem(const String &key); void removeItem(const String &key);
/*! /*!
* Adds to the text item specified by \a key the data \a value. If \a replace * Adds to the text item specified by \a key the data \a value.
* is true, then all of the other values on the same key will be removed * If \a replace is true, then all of the other values on the same key will be removed first.
* first. If a binary item exists for \a key it will be removed first. * If a binary item exists for \a key it will be removed first.
*/ */
void addValue(const String &key, const String &value, bool replace = true); void addValue(const String &key, const String &value, bool replace = true);
/*! /*!
* Set the binary data for the key specified by \a item to \a value * Set the binary data for the key specified by \a item to \a value
* This will convert the item to type \a Binary if it isn't already and * This will convert the item to type \a Binary if it isn't already and all of the other values on the same key will be removed.
* all of the other values on the same key will be removed. */
*/
void setData(const String &key, const ByteVector &value); void setData(const String &key, const ByteVector &value);
/*! /*!
* Sets the \a key item to the value of \a item. If an item with the \a key is already * Sets the \a key item to the value of \a item. If an item with the \a key is already present, it will be replaced.
* present, it will be replaced. */
*/
void setItem(const String &key, const Item &item); void setItem(const String &key, const Item &item);
/*! /*!
* Returns true if the tag does not contain any data. * Returns true if the tag does not contain any data.
*/ */
bool isEmpty() const; bool isEmpty() const;
protected: protected:
/*! /*!
* Reads from the file specified in the constructor. * Reads from the file specified in the constructor.
*/ */
void read(); void read();
/*! /*!
* Parses the body of the tag in \a data. * Parses the body of the tag in \a data.
*/ */
void parse(const ByteVector &data); void parse(const ByteVector &data);
private: private:

View File

@@ -35,10 +35,7 @@ using namespace Strawberry_TagLib::TagLib;
class ASF::Attribute::AttributePrivate : public RefCounter { class ASF::Attribute::AttributePrivate : public RefCounter {
public: public:
AttributePrivate() : pictureValue(ASF::Picture::fromInvalid()), AttributePrivate() : pictureValue(ASF::Picture::fromInvalid()), numericValue(0), stream(0), language(0) {}
numericValue(0),
stream(0),
language(0) {}
AttributeTypes type; AttributeTypes type;
String stringValue; String stringValue;
ByteVector byteVectorValue; ByteVector byteVectorValue;
@@ -146,6 +143,7 @@ ASF::Picture ASF::Attribute::toPicture() const {
} }
String ASF::Attribute::parse(ASF::File &f, int kind) { String ASF::Attribute::parse(ASF::File &f, int kind) {
unsigned int size, nameLength; unsigned int size, nameLength;
String name; String name;
d->pictureValue = Picture::fromInvalid(); d->pictureValue = Picture::fromInvalid();
@@ -214,9 +212,11 @@ String ASF::Attribute::parse(ASF::File &f, int kind) {
} }
return name; return name;
} }
int ASF::Attribute::dataSize() const { int ASF::Attribute::dataSize() const {
switch (d->type) { switch (d->type) {
case WordType: case WordType:
return 2; return 2;
@@ -236,9 +236,11 @@ int ASF::Attribute::dataSize() const {
return d->byteVectorValue.size(); return d->byteVectorValue.size();
} }
return 0; return 0;
} }
ByteVector ASF::Attribute::render(const String &name, int kind) const { ByteVector ASF::Attribute::render(const String &name, int kind) const {
ByteVector data; ByteVector data;
switch (d->type) { switch (d->type) {
@@ -296,6 +298,7 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const {
} }
return data; return data;
} }
int ASF::Attribute::language() const { int ASF::Attribute::language() const {

View File

@@ -33,7 +33,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ASF { namespace ASF {
class File; class File;
@@ -42,8 +41,8 @@ class Picture;
class TAGLIB_EXPORT Attribute { class TAGLIB_EXPORT Attribute {
public: public:
/*! /*!
* Enum of types an Attribute can have. * Enum of types an Attribute can have.
*/ */
enum AttributeTypes { enum AttributeTypes {
UnicodeType = 0, UnicodeType = 0,
BytesType = 1, BytesType = 1,
@@ -55,131 +54,131 @@ class TAGLIB_EXPORT Attribute {
}; };
/*! /*!
* Constructs an empty attribute. * Constructs an empty attribute.
*/ */
Attribute(); Attribute();
/*! /*!
* Constructs an attribute with \a key and a UnicodeType \a value. * Constructs an attribute with \a key and a UnicodeType \a value.
*/ */
Attribute(const String &value); Attribute(const String &value);
/*! /*!
* Constructs an attribute with \a key and a BytesType \a value. * Constructs an attribute with \a key and a BytesType \a value.
*/ */
Attribute(const ByteVector &value); Attribute(const ByteVector &value);
/*! /*!
* Constructs an attribute with \a key and a Picture \a value. * Constructs an attribute with \a key and a Picture \a value.
* *
* This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that, * This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that,
* while there may be any number of APIC frames associated with a file, * while there may be any number of APIC frames associated with a file,
* only one may be of type 1 and only one may be of type 2. * only one may be of type 1 and only one may be of type 2.
* *
* The specification also states that the description of the picture can be no longer than 64 characters, but can be empty. * The specification also states that the description of the picture can be no longer than 64 characters, but can be empty.
* WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications. * WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications.
* You must add code in your application to perform validations if you want to maintain complete compatibility with ID3. * You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
*/ */
Attribute(const Picture &value); Attribute(const Picture &value);
/*! /*!
* Constructs an attribute with \a key and a DWordType \a value. * Constructs an attribute with \a key and a DWordType \a value.
*/ */
Attribute(unsigned int value); Attribute(unsigned int value);
/*! /*!
* Constructs an attribute with \a key and a QWordType \a value. * Constructs an attribute with \a key and a QWordType \a value.
*/ */
Attribute(unsigned long long value); Attribute(unsigned long long value);
/*! /*!
* Constructs an attribute with \a key and a WordType \a value. * Constructs an attribute with \a key and a WordType \a value.
*/ */
Attribute(unsigned short value); Attribute(unsigned short value);
/*! /*!
* Constructs an attribute with \a key and a BoolType \a value. * Constructs an attribute with \a key and a BoolType \a value.
*/ */
Attribute(bool value); Attribute(bool value);
/*! /*!
* Construct an attribute as a copy of \a other. * Construct an attribute as a copy of \a other.
*/ */
Attribute(const Attribute &item); Attribute(const Attribute &item);
/*! /*!
* Copies the contents of \a other into this item. * Copies the contents of \a other into this item.
*/ */
Attribute &operator=(const Attribute &other); Attribute &operator=(const Attribute &other);
/*! /*!
* Exchanges the content of the Attribute by the content of \a other. * Exchanges the content of the Attribute by the content of \a other.
*/ */
void swap(Attribute &other); void swap(Attribute &other);
/*! /*!
* Destroys the attribute. * Destroys the attribute.
*/ */
virtual ~Attribute(); virtual ~Attribute();
/*! /*!
* Returns type of the value. * Returns type of the value.
*/ */
AttributeTypes type() const; AttributeTypes type() const;
/*! /*!
* Returns the BoolType \a value. * Returns the BoolType \a value.
*/ */
unsigned short toBool() const; unsigned short toBool() const;
/*! /*!
* Returns the WordType \a value. * Returns the WordType \a value.
*/ */
unsigned short toUShort() const; unsigned short toUShort() const;
/*! /*!
* Returns the DWordType \a value. * Returns the DWordType \a value.
*/ */
unsigned int toUInt() const; unsigned int toUInt() const;
/*! /*!
* Returns the QWordType \a value. * Returns the QWordType \a value.
*/ */
unsigned long long toULongLong() const; unsigned long long toULongLong() const;
/*! /*!
* Returns the UnicodeType \a value. * Returns the UnicodeType \a value.
*/ */
String toString() const; String toString() const;
/*! /*!
* Returns the BytesType \a value. * Returns the BytesType \a value.
*/ */
ByteVector toByteVector() const; ByteVector toByteVector() const;
/*! /*!
* Returns the Picture \a value. * Returns the Picture \a value.
*/ */
Picture toPicture() const; Picture toPicture() const;
/*! /*!
* Returns the language number, or 0 is no stream number was set. * Returns the language number, or 0 is no stream number was set.
*/ */
int language() const; int language() const;
/*! /*!
* Sets the language number. * Sets the language number.
*/ */
void setLanguage(int value); void setLanguage(int value);
/*! /*!
* Returns the stream number, or 0 is no stream number was set. * Returns the stream number, or 0 is no stream number was set.
*/ */
int stream() const; int stream() const;
/*! /*!
* Sets the stream number. * Sets the stream number.
*/ */
void setStream(int value); void setStream(int value);
#ifndef DO_NOT_DOCUMENT #ifndef DO_NOT_DOCUMENT
@@ -199,7 +198,6 @@ class TAGLIB_EXPORT Attribute {
AttributePrivate *d; AttributePrivate *d;
}; };
} // namespace ASF } // namespace ASF
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -50,13 +50,13 @@ class ASF::File::FilePrivate {
class MetadataLibraryObject; class MetadataLibraryObject;
FilePrivate() : headerSize(0), FilePrivate() : headerSize(0),
tag(0), tag(nullptr),
properties(0), properties(nullptr),
contentDescriptionObject(0), contentDescriptionObject(nullptr),
extendedContentDescriptionObject(0), extendedContentDescriptionObject(nullptr),
headerExtensionObject(0), headerExtensionObject(nullptr),
metadataObject(0), metadataObject(nullptr),
metadataLibraryObject(0) { metadataLibraryObject(nullptr) {
objects.setAutoDelete(true); objects.setAutoDelete(true);
} }
@@ -177,19 +177,20 @@ class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::B
}; };
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size) { void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size) {
data.clear(); data.clear();
if (size > 24 && size <= (unsigned int)(file->length())) if (size > 24 && size <= (unsigned int)(file->length()))
data = file->readBlock(size - 24); data = file->readBlock(size - 24);
else else
data = ByteVector(); data = ByteVector();
} }
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/) { ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/) {
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data; return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
} }
ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid) { ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid) {}
}
ByteVector ASF::File::FilePrivate::UnknownObject::guid() const { ByteVector ASF::File::FilePrivate::UnknownObject::guid() const {
return myGuid; return myGuid;
@@ -200,6 +201,7 @@ ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const {
} }
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size) { void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size) {
BaseObject::parse(file, size); BaseObject::parse(file, size);
if (data.size() < 64) { if (data.size() < 64) {
debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short."); debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short.");
@@ -209,6 +211,7 @@ void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsign
const long long duration = data.toLongLong(40, false); const long long duration = data.toLongLong(40, false);
const long long preroll = data.toLongLong(56, false); const long long preroll = data.toLongLong(56, false);
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5)); file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
} }
ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const { ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const {
@@ -216,6 +219,7 @@ ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const {
} }
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size) { void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size) {
BaseObject::parse(file, size); BaseObject::parse(file, size);
if (data.size() < 70) { if (data.size() < 70) {
debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short."); debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short.");
@@ -227,6 +231,7 @@ void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsi
file->d->properties->setSampleRate(data.toUInt(58, false)); file->d->properties->setSampleRate(data.toUInt(58, false));
file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5)); file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
file->d->properties->setBitsPerSample(data.toUShort(68, false)); file->d->properties->setBitsPerSample(data.toUShort(68, false));
} }
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const { ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const {
@@ -234,6 +239,7 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const {
} }
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) { void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) {
const int titleLength = readWORD(file); const int titleLength = readWORD(file);
const int artistLength = readWORD(file); const int artistLength = readWORD(file);
const int copyrightLength = readWORD(file); const int copyrightLength = readWORD(file);
@@ -244,9 +250,11 @@ void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, un
file->d->tag->setCopyright(readString(file, copyrightLength)); file->d->tag->setCopyright(readString(file, copyrightLength));
file->d->tag->setComment(readString(file, commentLength)); file->d->tag->setComment(readString(file, commentLength));
file->d->tag->setRating(readString(file, ratingLength)); file->d->tag->setRating(readString(file, ratingLength));
} }
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file) { ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file) {
const ByteVector v1 = renderString(file->d->tag->title()); const ByteVector v1 = renderString(file->d->tag->title());
const ByteVector v2 = renderString(file->d->tag->artist()); const ByteVector v2 = renderString(file->d->tag->artist());
const ByteVector v3 = renderString(file->d->tag->copyright()); const ByteVector v3 = renderString(file->d->tag->copyright());
@@ -264,6 +272,7 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *f
data.append(v4); data.append(v4);
data.append(v5); data.append(v5);
return BaseObject::render(file); return BaseObject::render(file);
} }
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const { ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const {
@@ -271,19 +280,23 @@ ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() cons
} }
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) { void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) {
int count = readWORD(file); int count = readWORD(file);
while (count--) { while (count--) {
ASF::Attribute attribute; ASF::Attribute attribute;
String name = attribute.parse(*file); String name = attribute.parse(*file);
file->d->tag->addAttribute(name, attribute); file->d->tag->addAttribute(name, attribute);
} }
} }
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file) { ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file) {
data.clear(); data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false)); data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(attributeData.toByteVector("")); data.append(attributeData.toByteVector(""));
return BaseObject::render(file); return BaseObject::render(file);
} }
ByteVector ASF::File::FilePrivate::MetadataObject::guid() const { ByteVector ASF::File::FilePrivate::MetadataObject::guid() const {
@@ -291,19 +304,23 @@ ByteVector ASF::File::FilePrivate::MetadataObject::guid() const {
} }
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/) { void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/) {
int count = readWORD(file); int count = readWORD(file);
while (count--) { while (count--) {
ASF::Attribute attribute; ASF::Attribute attribute;
String name = attribute.parse(*file, 1); String name = attribute.parse(*file, 1);
file->d->tag->addAttribute(name, attribute); file->d->tag->addAttribute(name, attribute);
} }
} }
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file) { ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file) {
data.clear(); data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false)); data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(attributeData.toByteVector("")); data.append(attributeData.toByteVector(""));
return BaseObject::render(file); return BaseObject::render(file);
} }
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const { ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const {
@@ -311,19 +328,23 @@ ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const {
} }
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/) { void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/) {
int count = readWORD(file); int count = readWORD(file);
while (count--) { while (count--) {
ASF::Attribute attribute; ASF::Attribute attribute;
String name = attribute.parse(*file, 2); String name = attribute.parse(*file, 2);
file->d->tag->addAttribute(name, attribute); file->d->tag->addAttribute(name, attribute);
} }
} }
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file) { ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file) {
data.clear(); data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false)); data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(attributeData.toByteVector("")); data.append(attributeData.toByteVector(""));
return BaseObject::render(file); return BaseObject::render(file);
} }
ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject() { ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject() {
@@ -335,6 +356,7 @@ ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const {
} }
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/) { void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/) {
file->seek(18, File::Current); file->seek(18, File::Current);
long long dataSize = readDWORD(file); long long dataSize = readDWORD(file);
long long dataPos = 0; long long dataPos = 0;
@@ -366,15 +388,18 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig
objects.append(obj); objects.append(obj);
dataPos += size; dataPos += size;
} }
} }
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file) { ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file) {
data.clear(); data.clear();
for (List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) { for (List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
data.append((*it)->render(file)); data.append((*it)->render(file));
} }
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data; data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
return BaseObject::render(file); return BaseObject::render(file);
} }
ByteVector ASF::File::FilePrivate::CodecListObject::guid() const { ByteVector ASF::File::FilePrivate::CodecListObject::guid() const {
@@ -382,6 +407,7 @@ ByteVector ASF::File::FilePrivate::CodecListObject::guid() const {
} }
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size) { void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size) {
BaseObject::parse(file, size); BaseObject::parse(file, size);
if (data.size() <= 20) { if (data.size() <= 20) {
debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short."); debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short.");
@@ -428,6 +454,7 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
break; break;
} }
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -435,24 +462,24 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool ASF::File::isSupported(IOStream *stream) { bool ASF::File::isSupported(IOStream *stream) {
// An ASF file has to start with the designated GUID. // An ASF file has to start with the designated GUID.
const ByteVector id = Utils::readHeader(stream, 16, false); const ByteVector id = Utils::readHeader(stream, 16, false);
return (id == headerGuid); return (id == headerGuid);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ASF::File::File(FileName file, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), ASF::File::File(FileName file, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(); read();
} }
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(); read();
} }
@@ -482,6 +509,7 @@ ASF::Properties *ASF::File::audioProperties() const {
} }
bool ASF::File::save() { bool ASF::File::save() {
if (readOnly()) { if (readOnly()) {
debug("ASF::File::save() -- File is read only."); debug("ASF::File::save() -- File is read only.");
return false; return false;
@@ -562,6 +590,7 @@ bool ASF::File::save() {
d->headerSize = data.size() + 30; d->headerSize = data.size() + 30;
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -569,6 +598,7 @@ bool ASF::File::save() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ASF::File::read() { void ASF::File::read() {
if (!isValid()) if (!isValid())
return; return;
@@ -594,8 +624,8 @@ void ASF::File::read() {
} }
seek(2, Current); seek(2, Current);
FilePrivate::FilePropertiesObject *filePropertiesObject = 0; FilePrivate::FilePropertiesObject *filePropertiesObject = nullptr;
FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0; FilePrivate::StreamPropertiesObject *streamPropertiesObject = nullptr;
for (int i = 0; i < numObjects; i++) { for (int i = 0; i < numObjects; i++) {
const ByteVector guid = readBlock(16); const ByteVector guid = readBlock(16);
if (guid.size() != 16) { if (guid.size() != 16) {
@@ -648,4 +678,5 @@ void ASF::File::read() {
setValid(false); setValid(false);
return; return;
} }
} }

View File

@@ -39,88 +39,84 @@ namespace TagLib {
namespace ASF { namespace ASF {
/*! /*!
* This implements and provides an interface for ASF files to the * This implements and provides an interface for ASF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional * the abstract TagLib::File API as well as providing some additional
* information specific to ASF files. * information specific to ASF files.
*/ */
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* Constructs an ASF file from \a file. * Constructs an ASF file from \a file.
* *
* \note In the current implementation, both \a readProperties and * \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always * \a propertiesStyle are ignored. The audio properties are always
* read. * read.
*/ */
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average); Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs an ASF file from \a stream. * Constructs an ASF file from \a stream.
* *
* \note In the current implementation, both \a readProperties and * \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always * \a propertiesStyle are ignored. The audio properties are always
* read. * read.
* *
* \note TagLib will *not* take ownership of the stream, the caller is * \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object. * responsible for deleting it after the File object.
*/ */
File(IOStream *stream, bool readProperties = true, File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
/*! /*!
* Returns a pointer to the ASF tag of the file. * Returns a pointer to the ASF tag of the file.
* *
* ASF::Tag implements the tag interface, so this serves as the * ASF::Tag implements the tag interface, so this serves as the
* reimplementation of TagLib::File::tag(). * reimplementation of TagLib::File::tag().
* *
* \note The Tag <b>is still</b> owned by the ASF::File and should not be * \note The Tag <b>is still</b> owned by the ASF::File and should not be
* deleted by the user. It will be deleted when the file (object) is * deleted by the user. It will be deleted when the file (object) is
* destroyed. * destroyed.
*/ */
virtual Tag *tag() const; virtual Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Removes unsupported properties. Forwards to the actual Tag's * Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
* removeUnsupportedProperties() function. */
*/
void removeUnsupportedProperties(const StringList &properties); void removeUnsupportedProperties(const StringList &properties);
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the ASF audio properties for this file. * Returns the ASF audio properties for this file.
*/ */
virtual Properties *audioProperties() const; virtual Properties *audioProperties() const;
/*! /*!
* Save the file. * Save the file.
* *
* This returns true if the save was successful. * This returns true if the save was successful.
*/ */
virtual bool save(); virtual bool save();
/*! /*!
* Returns whether or not the given \a stream can be opened as an ASF * Returns whether or not the given \a stream can be opened as an ASF file.
* file. *
* * \note This method is designed to do a quick check. The result may not necessarily be correct.
* \note This method is designed to do a quick check. The result may */
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
private: private:

View File

@@ -76,7 +76,7 @@ ASF::Picture::Type ASF::Picture::type() const {
return d->type; return d->type;
} }
void ASF::Picture::setType(const ASF::Picture::Type& t) { void ASF::Picture::setType(const ASF::Picture::Type &t) {
d->type = t; d->type = t;
} }
@@ -92,7 +92,7 @@ ByteVector ASF::Picture::picture() const {
return d->picture; return d->picture;
} }
void ASF::Picture::setPicture(const ByteVector& p) { void ASF::Picture::setPicture(const ByteVector &p) {
d->picture = p; d->picture = p;
} }
@@ -113,6 +113,7 @@ void ASF::Picture::swap(Picture& other) {
} }
ByteVector ASF::Picture::render() const { ByteVector ASF::Picture::render() const {
if (!isValid()) if (!isValid())
return ByteVector(); return ByteVector();
@@ -121,9 +122,11 @@ ByteVector ASF::Picture::render() const {
renderString(d->mimeType) + renderString(d->mimeType) +
renderString(d->description) + renderString(d->description) +
d->picture; d->picture;
} }
void ASF::Picture::parse(const ByteVector& bytes) { void ASF::Picture::parse(const ByteVector &bytes) {
d->valid = false; d->valid = false;
if (bytes.size() < 9) if (bytes.size() < 9)
return; return;
@@ -152,11 +155,13 @@ void ASF::Picture::parse(const ByteVector& bytes) {
d->picture = bytes.mid(pos, dataLen); d->picture = bytes.mid(pos, dataLen);
d->valid = true; d->valid = true;
return;
} }
ASF::Picture ASF::Picture::fromInvalid() { ASF::Picture ASF::Picture::fromInvalid() {
Picture ret; Picture ret;
ret.d->valid = false; ret.d->valid = false;
return ret; return ret;
} }

View File

@@ -38,18 +38,17 @@ namespace ASF {
//! An ASF attached picture interface implementation //! An ASF attached picture interface implementation
/*! /*!
* This is an implementation of ASF attached pictures interface. Pictures may be * This is an implementation of ASF attached pictures interface.
* included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture * Pictures may be included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture attribute in a single tag).
* attribute in a single tag). These pictures are usually in either JPEG or * These pictures are usually in either JPEG or PNG format.
* PNG format. * \see Attribute::toPicture()
* \see Attribute::toPicture() * \see Attribute::Attribute(const Picture& picture)
* \see Attribute::Attribute(const Picture& picture) */
*/
class TAGLIB_EXPORT Picture { class TAGLIB_EXPORT Picture {
public: public:
/*! /*!
* This describes the function or content of the picture. * This describes the function or content of the picture.
*/ */
enum Type { enum Type {
//! A type not enumerated below //! A type not enumerated below
Other = 0x00, Other = 0x00,
@@ -96,112 +95,109 @@ class TAGLIB_EXPORT Picture {
}; };
/*! /*!
* Constructs an empty picture. * Constructs an empty picture.
*/ */
Picture(); Picture();
/*! /*!
* Construct an picture as a copy of \a other. * Construct an picture as a copy of \a other.
*/ */
Picture(const Picture& other); Picture(const Picture& other);
/*! /*!
* Destroys the picture. * Destroys the picture.
*/ */
virtual ~Picture(); virtual ~Picture();
/*! /*!
* Copies the contents of \a other into this picture. * Copies the contents of \a other into this picture.
*/ */
Picture& operator=(const Picture& other); Picture& operator=(const Picture& other);
/*! /*!
* Exchanges the content of the Picture by the content of \a other. * Exchanges the content of the Picture by the content of \a other.
*/ */
void swap(Picture& other); void swap(Picture& other);
/*! /*!
* Returns true if Picture stores valid picture * Returns true if Picture stores valid picture
*/ */
bool isValid() const; bool isValid() const;
/*! /*!
* Returns the mime type of the image. This should in most cases be * Returns the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
* "image/png" or "image/jpeg". * \see setMimeType(const String &)
* \see setMimeType(const String &) * \see picture()
* \see picture() * \see setPicture(const ByteArray&)
* \see setPicture(const ByteArray&) */
*/
String mimeType() const; String mimeType() const;
/*! /*!
* Sets the mime type of the image. This should in most cases be * Sets the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
* "image/png" or "image/jpeg". * \see setMimeType(const String &)
* \see setMimeType(const String &) * \see picture()
* \see picture() * \see setPicture(const ByteArray&)
* \see setPicture(const ByteArray&) */
*/
void setMimeType(const String& value); void setMimeType(const String& value);
/*! /*!
* Returns the type of the image. * Returns the type of the image.
* *
* \see Type * \see Type
* \see setType() * \see setType()
*/ */
Type type() const; Type type() const;
/*! /*!
* Sets the type for the image. * Sets the type for the image.
* *
* \see Type * \see Type
* \see type() * \see type()
*/ */
void setType(const ASF::Picture::Type& t); void setType(const ASF::Picture::Type& t);
/*! /*!
* Returns a text description of the image. * Returns a text description of the image.
* *
* \see setDescription() * \see setDescription()
*/ */
String description() const; String description() const;
/*! /*!
* Sets a textual description of the image to \a desc. * Sets a textual description of the image to \a desc.
* *
* \see description() * \see description()
*/ */
void setDescription(const String& desc); void setDescription(const String& desc);
/*! /*!
* Returns the image data as a ByteVector. * Returns the image data as a ByteVector.
* *
* \note ByteVector has a data() method that returns a const char * which * \note ByteVector has a data() method that returns a const char * which should make it easy to export this data to external programs.
* should make it easy to export this data to external programs. *
* * \see setPicture()
* \see setPicture() * \see mimeType()
* \see mimeType() */
*/
ByteVector picture() const; ByteVector picture() const;
/*! /*!
* Sets the image data to \a p. \a p should be of the type specified in * Sets the image data to \a p.
* this frame's mime-type specification. * \a p should be of the type specified in this frame's mime-type specification.
* *
* \see picture() * \see picture()
* \see mimeType() * \see mimeType()
* \see setMimeType() * \see setMimeType()
*/ */
void setPicture(const ByteVector& p); void setPicture(const ByteVector& p);
/*! /*!
* Returns picture as binary raw data \a value * Returns picture as binary raw data \a value
*/ */
ByteVector render() const; ByteVector render() const;
/*! /*!
* Returns picture as binary raw data \a value * Returns picture as binary raw data \a value
*/ */
int dataSize() const; int dataSize() const;
#ifndef DO_NOT_DOCUMENT #ifndef DO_NOT_DOCUMENT

View File

@@ -62,10 +62,6 @@ ASF::Properties::~Properties() {
delete d; delete d;
} }
int ASF::Properties::length() const {
return lengthInSeconds();
}
int ASF::Properties::lengthInSeconds() const { int ASF::Properties::lengthInSeconds() const {
return d->length / 1000; return d->length / 1000;
} }
@@ -135,6 +131,7 @@ void ASF::Properties::setBitsPerSample(int value) {
} }
void ASF::Properties::setCodec(int value) { void ASF::Properties::setCodec(int value) {
switch (value) { switch (value) {
case 0x0160: case 0x0160:
d->codec = WMA1; d->codec = WMA1;
@@ -152,6 +149,7 @@ void ASF::Properties::setCodec(int value) {
d->codec = Unknown; d->codec = Unknown;
break; break;
} }
} }
void ASF::Properties::setCodecName(const String &value) { void ASF::Properties::setCodecName(const String &value) {

View File

@@ -32,129 +32,116 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ASF { namespace ASF {
//! An implementation of ASF audio properties //! An implementation of ASF audio properties
class TAGLIB_EXPORT Properties : public AudioProperties { class TAGLIB_EXPORT Properties : public AudioProperties {
public: public:
/*! /*!
* Audio codec types can be used in ASF file. * Audio codec types can be used in ASF file.
*/ */
enum Codec { enum Codec {
/*! /*!
* Couldn't detect the codec. * Couldn't detect the codec.
*/ */
Unknown = 0, Unknown = 0,
/*! /*!
* Windows Media Audio 1 * Windows Media Audio 1
*/ */
WMA1, WMA1,
/*! /*!
* Windows Media Audio 2 or above * Windows Media Audio 2 or above
*/ */
WMA2, WMA2,
/*! /*!
* Windows Media Audio 9 Professional * Windows Media Audio 9 Professional
*/ */
WMA9Pro, WMA9Pro,
/*! /*!
* Windows Media Audio 9 Lossless * Windows Media Audio 9 Lossless
*/ */
WMA9Lossless, WMA9Lossless,
}; };
/*! /*!
* Creates an instance of ASF::Properties. * Creates an instance of ASF::Properties.
*/ */
Properties(); Properties();
/*! /*!
* Destroys this ASF::Properties instance. * Destroys this ASF::Properties instance.
*/ */
virtual ~Properties(); virtual ~Properties();
/*! /*!
* Returns the length of the file in seconds. The length is rounded down to * Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second. * the nearest whole second.
* *
* \note This method is just an alias of lengthInSeconds(). * \see lengthInMilliseconds()
* */
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual // BIC: make virtual
int lengthInSeconds() const; int lengthInSeconds() const;
/*! /*!
* Returns the length of the file in milliseconds. * Returns the length of the file in milliseconds.
* *
* \see lengthInSeconds() * \see lengthInSeconds()
*/ */
// BIC: make virtual // BIC: make virtual
int lengthInMilliseconds() const; int lengthInMilliseconds() const;
/*! /*!
* Returns the average bit rate of the file in kb/s. * Returns the average bit rate of the file in kb/s.
*/ */
virtual int bitrate() const; virtual int bitrate() const;
/*! /*!
* Returns the sample rate in Hz. * Returns the sample rate in Hz.
*/ */
virtual int sampleRate() const; virtual int sampleRate() const;
/*! /*!
* Returns the number of audio channels. * Returns the number of audio channels.
*/ */
virtual int channels() const; virtual int channels() const;
/*! /*!
* Returns the number of bits per audio sample. * Returns the number of bits per audio sample.
*/ */
int bitsPerSample() const; int bitsPerSample() const;
/*! /*!
* Returns the codec used in the file. * Returns the codec used in the file.
* *
* \see codecName() * \see codecName()
* \see codecDescription() * \see codecDescription()
*/ */
Codec codec() const; Codec codec() const;
/*! /*!
* Returns the concrete codec name, for example "Windows Media Audio 9.1" * Returns the concrete codec name, for example "Windows Media Audio 9.1" used in the file if available, otherwise an empty string.
* used in the file if available, otherwise an empty string. *
* * \see codec()
* \see codec() * \see codecDescription()
* \see codecDescription() */
*/
String codecName() const; String codecName() const;
/*! /*!
* Returns the codec description, typically contains the encoder settings, * Returns the codec description, typically contains the encoder settings,
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available, * for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available, otherwise an empty string.
* otherwise an empty string. *
* * \see codec()
* \see codec() * \see codecName()
* \see codecName() */
*/
String codecDescription() const; String codecDescription() const;
/*! /*!
* Returns whether or not the file is encrypted. * Returns whether or not the file is encrypted.
*/ */
bool isEncrypted() const; bool isEncrypted() const;
#ifndef DO_NOT_DOCUMENT #ifndef DO_NOT_DOCUMENT

View File

@@ -38,8 +38,7 @@ class ASF::Tag::TagPrivate {
AttributeListMap attributeListMap; AttributeListMap attributeListMap;
}; };
ASF::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), ASF::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), d(new TagPrivate()) {
d(new TagPrivate()) {
} }
ASF::Tag::~Tag() { ASF::Tag::~Tag() {
@@ -55,9 +54,11 @@ String ASF::Tag::artist() const {
} }
String ASF::Tag::album() const { String ASF::Tag::album() const {
if (d->attributeListMap.contains("WM/AlbumTitle")) if (d->attributeListMap.contains("WM/AlbumTitle"))
return d->attributeListMap["WM/AlbumTitle"][0].toString(); return d->attributeListMap["WM/AlbumTitle"][0].toString();
return String(); return String();
} }
String ASF::Tag::copyright() const { String ASF::Tag::copyright() const {
@@ -73,12 +74,15 @@ String ASF::Tag::rating() const {
} }
unsigned int ASF::Tag::year() const { unsigned int ASF::Tag::year() const {
if (d->attributeListMap.contains("WM/Year")) if (d->attributeListMap.contains("WM/Year"))
return d->attributeListMap["WM/Year"][0].toString().toInt(); return d->attributeListMap["WM/Year"][0].toString().toInt();
return 0; return 0;
} }
unsigned int ASF::Tag::track() const { unsigned int ASF::Tag::track() const {
if (d->attributeListMap.contains("WM/TrackNumber")) { if (d->attributeListMap.contains("WM/TrackNumber")) {
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0]; const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
if (attr.type() == ASF::Attribute::DWordType) if (attr.type() == ASF::Attribute::DWordType)
@@ -89,12 +93,15 @@ unsigned int ASF::Tag::track() const {
if (d->attributeListMap.contains("WM/Track")) if (d->attributeListMap.contains("WM/Track"))
return d->attributeListMap["WM/Track"][0].toUInt(); return d->attributeListMap["WM/Track"][0].toUInt();
return 0; return 0;
} }
String ASF::Tag::genre() const { String ASF::Tag::genre() const {
if (d->attributeListMap.contains("WM/Genre")) if (d->attributeListMap.contains("WM/Genre"))
return d->attributeListMap["WM/Genre"][0].toString(); return d->attributeListMap["WM/Genre"][0].toString();
return String(); return String();
} }
void ASF::Tag::setTitle(const String &value) { void ASF::Tag::setTitle(const String &value) {
@@ -133,11 +140,7 @@ void ASF::Tag::setTrack(unsigned int value) {
setAttribute("WM/TrackNumber", String::number(value)); setAttribute("WM/TrackNumber", String::number(value));
} }
ASF::AttributeListMap &ASF::Tag::attributeListMap() { const ASF::AttributeListMap ASF::Tag::attributeListMap() const {
return d->attributeListMap;
}
const ASF::AttributeListMap &ASF::Tag::attributeListMap() const {
return d->attributeListMap; return d->attributeListMap;
} }
@@ -154,9 +157,11 @@ ASF::AttributeList ASF::Tag::attribute(const String &name) const {
} }
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute) { void ASF::Tag::setAttribute(const String &name, const Attribute &attribute) {
AttributeList value; AttributeList value;
value.append(attribute); value.append(attribute);
d->attributeListMap.insert(name, value); d->attributeListMap.insert(name, value);
} }
void ASF::Tag::setAttribute(const String &name, const AttributeList &values) { void ASF::Tag::setAttribute(const String &name, const AttributeList &values) {
@@ -164,19 +169,23 @@ void ASF::Tag::setAttribute(const String &name, const AttributeList &values) {
} }
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute) { void ASF::Tag::addAttribute(const String &name, const Attribute &attribute) {
if (d->attributeListMap.contains(name)) { if (d->attributeListMap.contains(name)) {
d->attributeListMap[name].append(attribute); d->attributeListMap[name].append(attribute);
} }
else { else {
setAttribute(name, attribute); setAttribute(name, attribute);
} }
} }
bool ASF::Tag::isEmpty() const { bool ASF::Tag::isEmpty() const {
return Strawberry_TagLib::TagLib::Tag::isEmpty() && return Strawberry_TagLib::TagLib::Tag::isEmpty() &&
copyright().isEmpty() && copyright().isEmpty() &&
rating().isEmpty() && rating().isEmpty() &&
d->attributeListMap.isEmpty(); d->attributeListMap.isEmpty();
} }
namespace { namespace {
@@ -224,16 +233,19 @@ const char *keyTranslation[][2] = {
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]); const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
String translateKey(const String &key) { String translateKey(const String &key) {
for (size_t i = 0; i < keyTranslationSize; ++i) { for (size_t i = 0; i < keyTranslationSize; ++i) {
if (key == keyTranslation[i][0]) if (key == keyTranslation[i][0])
return keyTranslation[i][1]; return keyTranslation[i][1];
} }
return String(); return String();
} }
} // namespace } // namespace
PropertyMap ASF::Tag::properties() const { PropertyMap ASF::Tag::properties() const {
PropertyMap props; PropertyMap props;
if (!d->title.isEmpty()) { if (!d->title.isEmpty()) {
@@ -271,15 +283,19 @@ PropertyMap ASF::Tag::properties() const {
} }
} }
return props; return props;
} }
void ASF::Tag::removeUnsupportedProperties(const StringList &props) { void ASF::Tag::removeUnsupportedProperties(const StringList &props) {
StringList::ConstIterator it = props.begin(); StringList::ConstIterator it = props.begin();
for (; it != props.end(); ++it) for (; it != props.end(); ++it)
d->attributeListMap.erase(*it); d->attributeListMap.erase(*it);
} }
PropertyMap ASF::Tag::setProperties(const PropertyMap &props) { PropertyMap ASF::Tag::setProperties(const PropertyMap &props) {
static Map<String, String> reverseKeyMap; static Map<String, String> reverseKeyMap;
if (reverseKeyMap.isEmpty()) { if (reverseKeyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
@@ -339,4 +355,5 @@ PropertyMap ASF::Tag::setProperties(const PropertyMap &props) {
} }
return ignoredProps; return ignoredProps;
} }

View File

@@ -50,150 +50,135 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
virtual ~Tag(); virtual ~Tag();
/*! /*!
* Returns the track name. * Returns the track name.
*/ */
virtual String title() const; virtual String title() const;
/*! /*!
* Returns the artist name. * Returns the artist name.
*/ */
virtual String artist() const; virtual String artist() const;
/*! /*!
* Returns the album name; if no album name is present in the tag * Returns the album name; if no album name is present in the tag String::null will be returned.
* String::null will be returned. */
*/
virtual String album() const; virtual String album() const;
/*! /*!
* Returns the track comment. * Returns the track comment.
*/ */
virtual String comment() const; virtual String comment() const;
/*! /*!
* Returns the genre name; if no genre is present in the tag String::null * Returns the genre name; if no genre is present in the tag String::null will be returned.
* will be returned. */
*/
virtual String genre() const; virtual String genre() const;
/*! /*!
* Returns the rating. * Returns the rating.
*/ */
virtual String rating() const; virtual String rating() const;
/*! /*!
* Returns the genre name; if no genre is present in the tag String::null * Returns the genre name; if no genre is present in the tag String::null will be returned.
* will be returned. */
*/
virtual String copyright() const; virtual String copyright() const;
/*! /*!
* Returns the year; if there is no year set, this will return 0. * Returns the year; if there is no year set, this will return 0.
*/ */
virtual unsigned int year() const; virtual unsigned int year() const;
/*! /*!
* Returns the track number; if there is no track number set, this will * Returns the track number; if there is no track number set, this will return 0.
* return 0. */
*/
virtual unsigned int track() const; virtual unsigned int track() const;
/*! /*!
* Sets the title to \a s. * Sets the title to \a s.
*/ */
virtual void setTitle(const String &s); virtual void setTitle(const String &s);
/*! /*!
* Sets the artist to \a s. * Sets the artist to \a s.
*/ */
virtual void setArtist(const String &s); virtual void setArtist(const String &s);
/*! /*!
* Sets the album to \a s. If \a s is String::null then this value will be * Sets the album to \a s. If \a s is String::null then this value will be cleared.
* cleared. */
*/
virtual void setAlbum(const String &s); virtual void setAlbum(const String &s);
/*! /*!
* Sets the comment to \a s. * Sets the comment to \a s.
*/ */
virtual void setComment(const String &s); virtual void setComment(const String &s);
/*! /*!
* Sets the rating to \a s. * Sets the rating to \a s.
*/ */
virtual void setRating(const String &s); virtual void setRating(const String &s);
/*! /*!
* Sets the copyright to \a s. * Sets the copyright to \a s.
*/ */
virtual void setCopyright(const String &s); virtual void setCopyright(const String &s);
/*! /*!
* Sets the genre to \a s. * Sets the genre to \a s.
*/ */
virtual void setGenre(const String &s); virtual void setGenre(const String &s);
/*! /*!
* Sets the year to \a i. If \a s is 0 then this value will be cleared. * Sets the year to \a i. If \a s is 0 then this value will be cleared.
*/ */
virtual void setYear(unsigned int i); virtual void setYear(unsigned int i);
/*! /*!
* Sets the track to \a i. If \a s is 0 then this value will be cleared. * Sets the track to \a i. If \a s is 0 then this value will be cleared.
*/ */
virtual void setTrack(unsigned int i); virtual void setTrack(unsigned int i);
/*! /*!
* Returns true if the tag does not contain any data. This should be * Returns true if the tag does not contain any data.
* reimplemented in subclasses that provide more than the basic tagging * This should be reimplemented in subclasses that provide more than the basic tagging abilities in this class.
* abilities in this class. */
*/
virtual bool isEmpty() const; virtual bool isEmpty() const;
/*! /*!
* \deprecated * Returns a reference to the item list map. This is an AttributeListMap of all of the items in the tag.
*/ */
AttributeListMap &attributeListMap(); const AttributeListMap attributeListMap() const;
/*! /*!
* Returns a reference to the item list map. This is an AttributeListMap of * \return True if a value for \a attribute is currently set.
* all of the items in the tag. */
*/
// BIC: return by value
const AttributeListMap &attributeListMap() const;
/*!
* \return True if a value for \a attribute is currently set.
*/
bool contains(const String &name) const; bool contains(const String &name) const;
/*! /*!
* Removes the \a key attribute from the tag * Removes the \a key attribute from the tag
*/ */
void removeItem(const String &name); void removeItem(const String &name);
/*! /*!
* \return The list of values for the key \a name, or an empty list if no * \return The list of values for the key \a name, or an empty list if no values have been set.
* values have been set. */
*/
AttributeList attribute(const String &name) const; AttributeList attribute(const String &name) const;
/*! /*!
* Sets the \a key attribute to the value of \a attribute. If an attribute * Sets the \a key attribute to the value of \a attribute. If an attribute with the \a key is already present, it will be replaced.
* with the \a key is already present, it will be replaced. */
*/
void setAttribute(const String &name, const Attribute &attribute); void setAttribute(const String &name, const Attribute &attribute);
/*! /*!
* Sets multiple \a values to the key \a name. * Sets multiple \a values to the key \a name.
*/ */
void setAttribute(const String &name, const AttributeList &values); void setAttribute(const String &name, const AttributeList &values);
/*! /*!
* Sets the \a key attribute to the value of \a attribute. If an attribute * Sets the \a key attribute to the value of \a attribute. If an attribute
* with the \a key is already present, it will be added to the list. * with the \a key is already present, it will be added to the list.
*/ */
void addAttribute(const String &name, const Attribute &attribute); void addAttribute(const String &name, const Attribute &attribute);
PropertyMap properties() const; PropertyMap properties() const;

View File

@@ -89,8 +89,7 @@ class AudioProperties::AudioPropertiesPrivate {
// public methods // public methods
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AudioProperties::~AudioProperties() { AudioProperties::~AudioProperties() {}
}
int AudioProperties::lengthInSeconds() const { int AudioProperties::lengthInSeconds() const {
VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0) VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0)
@@ -104,5 +103,4 @@ int AudioProperties::lengthInMilliseconds() const {
// protected methods // protected methods
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AudioProperties::AudioProperties(ReadStyle) : d(0) { AudioProperties::AudioProperties(ReadStyle) : d(nullptr) {}
}

View File

@@ -34,21 +34,20 @@ namespace TagLib {
//! A simple, abstract interface to common audio properties //! A simple, abstract interface to common audio properties
/*! /*!
* The values here are common to most audio formats. For more specific, codec * The values here are common to most audio formats.
* dependent values, please see see the subclasses APIs. This is meant to * For more specific, codec dependent values, please see see the subclasses APIs.
* compliment the TagLib::File and TagLib::Tag APIs in providing a simple * This is meant to compliment the TagLib::File and TagLib::Tag APIs in providing a simple
* interface that is sufficient for most applications. * interface that is sufficient for most applications.
*/ */
class TAGLIB_EXPORT AudioProperties { class TAGLIB_EXPORT AudioProperties {
public: public:
/*! /*!
* Reading audio properties from a file can sometimes be very time consuming * Reading audio properties from a file can sometimes be very time consuming
* and for the most accurate results can often involve reading the entire * and for the most accurate results can often involve reading the entire file.
* file. Because in many situations speed is critical or the accuracy of the * Because in many situations speed is critical or the accuracy of the values
* values is not particularly important this allows the level of desired * is not particularly important this allows the level of desired accuracy to be set.
* accuracy to be set. */
*/
enum ReadStyle { enum ReadStyle {
//! Read as little of the file as possible //! Read as little of the file as possible
Fast, Fast,
@@ -59,57 +58,55 @@ class TAGLIB_EXPORT AudioProperties {
}; };
/*! /*!
* Destroys this AudioProperties instance. * Destroys this AudioProperties instance.
*/ */
virtual ~AudioProperties(); virtual ~AudioProperties();
/*! /*!
* Returns the length of the file in seconds. * Returns the length of the file in seconds.
*/ */
virtual int length() const = 0; //virtual int length() const = 0;
/*! /*!
* Returns the length of the file in seconds. The length is rounded down to * Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
* the nearest whole second. *
* * \see lengthInMilliseconds()
* \see lengthInMilliseconds() */
*/
// BIC: make virtual // BIC: make virtual
int lengthInSeconds() const; int lengthInSeconds() const;
/*! /*!
* Returns the length of the file in milliseconds. * Returns the length of the file in milliseconds.
* *
* \see lengthInSeconds() * \see lengthInSeconds()
*/ */
// BIC: make virtual // BIC: make virtual
int lengthInMilliseconds() const; int lengthInMilliseconds() const;
/*! /*!
* Returns the most appropriate bit rate for the file in kb/s. For constant * Returns the most appropriate bit rate for the file in kb/s. For constant bitrate formats this is simply the bitrate of the file.
* bitrate formats this is simply the bitrate of the file. For variable * For variable bitrate formats this is either the average or nominal bitrate.
* bitrate formats this is either the average or nominal bitrate. */
*/
virtual int bitrate() const = 0; virtual int bitrate() const = 0;
/*! /*!
* Returns the sample rate in Hz. * Returns the sample rate in Hz.
*/ */
virtual int sampleRate() const = 0; virtual int sampleRate() const = 0;
/*! /*!
* Returns the number of audio channels. * Returns the number of audio channels.
*/ */
virtual int channels() const = 0; virtual int channels() const = 0;
protected: protected:
/*! /*!
* Construct an audio properties instance. This is protected as this class * Construct an audio properties instance.
* should not be instantiated directly, but should be instantiated via its * This is protected as this class should not be instantiated directly,
* subclasses and can be fetched from the FileRef or File APIs. * but should be instantiated via its subclasses and can be fetched from the FileRef or File APIs.
* *
* \see ReadStyle * \see ReadStyle
*/ */
AudioProperties(ReadStyle style); AudioProperties(ReadStyle style);
private: private:

View File

@@ -76,42 +76,44 @@ unsigned int DSDIFF::DIIN::Tag::track() const {
} }
void DSDIFF::DIIN::Tag::setTitle(const String &title) { void DSDIFF::DIIN::Tag::setTitle(const String &title) {
if (title.isNull() || title.isEmpty()) if (title.isNull() || title.isEmpty())
d->title = String(); d->title = String();
else else
d->title = title; d->title = title;
} }
void DSDIFF::DIIN::Tag::setArtist(const String &artist) { void DSDIFF::DIIN::Tag::setArtist(const String &artist) {
if (artist.isNull() || artist.isEmpty()) if (artist.isNull() || artist.isEmpty())
d->artist = String(); d->artist = String();
else else
d->artist = artist; d->artist = artist;
} }
void DSDIFF::DIIN::Tag::setAlbum(const String &) { void DSDIFF::DIIN::Tag::setAlbum(const String &) {}
}
void DSDIFF::DIIN::Tag::setComment(const String &) { void DSDIFF::DIIN::Tag::setComment(const String &) {}
}
void DSDIFF::DIIN::Tag::setGenre(const String &) { void DSDIFF::DIIN::Tag::setGenre(const String &) {}
}
void DSDIFF::DIIN::Tag::setYear(unsigned int) { void DSDIFF::DIIN::Tag::setYear(unsigned int) {}
}
void DSDIFF::DIIN::Tag::setTrack(unsigned int) { void DSDIFF::DIIN::Tag::setTrack(unsigned int) {}
}
PropertyMap DSDIFF::DIIN::Tag::properties() const { PropertyMap DSDIFF::DIIN::Tag::properties() const {
PropertyMap properties; PropertyMap properties;
properties["TITLE"] = d->title; properties["TITLE"] = d->title;
properties["ARTIST"] = d->artist; properties["ARTIST"] = d->artist;
return properties; return properties;
} }
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps) { PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps) {
PropertyMap properties(origProps); PropertyMap properties(origProps);
properties.removeEmpty(); properties.removeEmpty();
StringList oneValueSet; StringList oneValueSet;
@@ -140,4 +142,5 @@ PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps) {
} }
return properties; return properties;
} }

View File

@@ -30,109 +30,103 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace DSDIFF { namespace DSDIFF {
namespace DIIN { namespace DIIN {
/*! /*!
* Tags from the Edited Master Chunk Info * Tags from the Edited Master Chunk Info
* *
* Only Title and Artist tags are supported * Only Title and Artist tags are supported
*/ */
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public: public:
Tag(); Tag();
virtual ~Tag(); virtual ~Tag();
/*! /*!
* Returns the track name; if no track name is present in the tag * Returns the track name; if no track name is present in the tag String() will be returned.
* String() will be returned. */
*/
String title() const; String title() const;
/*! /*!
* Returns the artist name; if no artist name is present in the tag * Returns the artist name; if no artist name is present in the tag String() will be returned.
* String() will be returned. */
*/
String artist() const; String artist() const;
/*! /*!
* Not supported. Therefore always returns String(). * Not supported. Therefore always returns String().
*/ */
String album() const; String album() const;
/*! /*!
* Not supported. Therefore always returns String(). * Not supported. Therefore always returns String().
*/ */
String comment() const; String comment() const;
/*! /*!
* Not supported. Therefore always returns String(). * Not supported. Therefore always returns String().
*/ */
String genre() const; String genre() const;
/*! /*!
* Not supported. Therefore always returns 0. * Not supported. Therefore always returns 0.
*/ */
unsigned int year() const; unsigned int year() const;
/*! /*!
* Not supported. Therefore always returns 0. * Not supported. Therefore always returns 0.
*/ */
unsigned int track() const; unsigned int track() const;
/*! /*!
* Sets the title to \a title. If \a title is String() then this * Sets the title to \a title. If \a title is String() then this value will be cleared.
* value will be cleared. */
*/
void setTitle(const String &title); void setTitle(const String &title);
/*! /*!
* Sets the artist to \a artist. If \a artist is String() then this * Sets the artist to \a artist. If \a artist is String() then this value will be cleared.
* value will be cleared. */
*/
void setArtist(const String &artist); void setArtist(const String &artist);
/*! /*!
* Not supported and therefore ignored. * Not supported and therefore ignored.
*/ */
void setAlbum(const String &album); void setAlbum(const String &album);
/*! /*!
* Not supported and therefore ignored. * Not supported and therefore ignored.
*/ */
void setComment(const String &comment); void setComment(const String &comment);
/*! /*!
* Not supported and therefore ignored. * Not supported and therefore ignored.
*/ */
void setGenre(const String &genre); void setGenre(const String &genre);
/*! /*!
* Not supported and therefore ignored. * Not supported and therefore ignored.
*/ */
void setYear(unsigned int year); void setYear(unsigned int year);
/*! /*!
* Not supported and therefore ignored. * Not supported and therefore ignored.
*/ */
void setTrack(unsigned int track); void setTrack(unsigned int track);
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* Since the DIIN tag is very limited, the exported map is as well. * Since the DIIN tag is very limited, the exported map is as well.
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* Because of the limitations of the DIIN file tag, any tags besides * Because of the limitations of the DIIN file tag, any tags besides
* TITLE and ARTIST, will be * TITLE and ARTIST, will be returned.
* returned. Additionally, if the map contains tags with multiple values, * Additionally, if the map contains tags with multiple values,
* all but the first will be contained in the returned map of unsupported * all but the first will be contained in the returned map of unsupported properties.
* properties. */
*/
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
private: private:

View File

@@ -23,6 +23,7 @@
* http://www.mozilla.org/MPL/ * * http://www.mozilla.org/MPL/ *
***************************************************************************/ ***************************************************************************/
#include <tstring.h>
#include <tbytevector.h> #include <tbytevector.h>
#include <tdebug.h> #include <tdebug.h>
#include <id3v2tag.h> #include <id3v2tag.h>
@@ -48,15 +49,18 @@ struct Chunk64 {
typedef std::vector<Chunk64> ChunkList; typedef std::vector<Chunk64> ChunkList;
int chunkIndex(const ChunkList &chunks, const ByteVector &id) { int chunkIndex(const ChunkList &chunks, const ByteVector &id) {
for (unsigned long int i = 0; i < chunks.size(); i++) { for (unsigned long int i = 0; i < chunks.size(); i++) {
if (chunks[i].name == id) if (chunks[i].name == id)
return i; return i;
} }
return -1; return -1;
} }
bool isValidChunkID(const ByteVector &name) { bool isValidChunkID(const ByteVector &name) {
if (name.size() != 4) if (name.size() != 4)
return false; return false;
@@ -66,6 +70,7 @@ bool isValidChunkID(const ByteVector &name) {
} }
return true; return true;
} }
enum { enum {
@@ -84,7 +89,7 @@ class DSDIFF::File::FilePrivate {
size(0), size(0),
isID3InPropChunk(false), isID3InPropChunk(false),
duplicateID3V2chunkIndex(-1), duplicateID3V2chunkIndex(-1),
properties(0), properties(nullptr),
id3v2TagChunkID("ID3 "), id3v2TagChunkID("ID3 "),
hasID3v2(false), hasID3v2(false),
hasDiin(false) { hasDiin(false) {
@@ -128,30 +133,34 @@ class DSDIFF::File::FilePrivate {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool DSDIFF::File::isSupported(IOStream *stream) { bool DSDIFF::File::isSupported(IOStream *stream) {
// A DSDIFF file has to start with "FRM8????????DSD ". // A DSDIFF file has to start with "FRM8????????DSD ".
const ByteVector id = Utils::readHeader(stream, 16, false); const ByteVector id = Utils::readHeader(stream, 16, false);
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12)); return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DSDIFF::File::File(FileName file, bool readProperties, DSDIFF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file) {
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file) {
d = new FilePrivate; d = new FilePrivate;
d->endianness = BigEndian; d->endianness = BigEndian;
if (isOpen()) if (isOpen())
read(readProperties, propertiesStyle); read(readProperties, propertiesStyle);
} }
DSDIFF::File::File(IOStream *stream, bool readProperties, DSDIFF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream) {
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream) {
d = new FilePrivate; d = new FilePrivate;
d->endianness = BigEndian; d->endianness = BigEndian;
if (isOpen()) if (isOpen())
read(readProperties, propertiesStyle); read(readProperties, propertiesStyle);
} }
DSDIFF::File::~File() { DSDIFF::File::~File() {
@@ -179,18 +188,22 @@ bool DSDIFF::File::hasDIINTag() const {
} }
PropertyMap DSDIFF::File::properties() const { PropertyMap DSDIFF::File::properties() const {
if (d->hasID3v2) if (d->hasID3v2)
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties(); return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
return PropertyMap(); return PropertyMap();
} }
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported) { void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported) {
if (d->hasID3v2) if (d->hasID3v2)
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported); d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported);
if (d->hasDiin) if (d->hasDiin)
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported); d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported);
} }
PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties) { PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties) {
@@ -206,6 +219,7 @@ bool DSDIFF::File::save() {
} }
bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) { bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) {
if (readOnly()) { if (readOnly()) {
debug("DSDIFF::File::save() -- File is read only."); debug("DSDIFF::File::save() -- File is read only.");
return false; return false;
@@ -279,9 +293,11 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) {
} }
return true; return true;
} }
void DSDIFF::File::strip(TagTypes tags) { void DSDIFF::File::strip(TagTypes tags) {
if (tags & ID3v2) { if (tags & ID3v2) {
removeRootChunk("ID3 "); removeRootChunk("ID3 ");
removeRootChunk("id3 "); removeRootChunk("id3 ");
@@ -296,6 +312,7 @@ void DSDIFF::File::strip(TagTypes tags) {
d->hasDiin = false; d->hasDiin = false;
d->tag.set(DIINIndex, new DIIN::Tag); d->tag.set(DIINIndex, new DIIN::Tag);
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -303,6 +320,7 @@ void DSDIFF::File::strip(TagTypes tags) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void DSDIFF::File::removeRootChunk(unsigned int i) { void DSDIFF::File::removeRootChunk(unsigned int i) {
unsigned long long chunkSize = d->chunks[i].size + d->chunks[i].padding + 12; unsigned long long chunkSize = d->chunks[i].size + d->chunks[i].padding + 12;
d->size -= chunkSize; d->size -= chunkSize;
@@ -316,16 +334,20 @@ void DSDIFF::File::removeRootChunk(unsigned int i) {
d->chunks[r].offset = d->chunks[r - 1].offset + 12 + d->chunks[r - 1].size + d->chunks[r - 1].padding; d->chunks[r].offset = d->chunks[r - 1].offset + 12 + d->chunks[r - 1].size + d->chunks[r - 1].padding;
d->chunks.erase(d->chunks.begin() + i); d->chunks.erase(d->chunks.begin() + i);
} }
void DSDIFF::File::removeRootChunk(const ByteVector &id) { void DSDIFF::File::removeRootChunk(const ByteVector &id) {
int i = chunkIndex(d->chunks, id); int i = chunkIndex(d->chunks, id);
if (i >= 0) if (i >= 0)
removeRootChunk(i); removeRootChunk(i);
} }
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data) { void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data) {
if (data.isEmpty()) { if (data.isEmpty()) {
removeRootChunk(i); removeRootChunk(i);
return; return;
@@ -350,9 +372,11 @@ void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data) {
// Finally update the internal offsets // Finally update the internal offsets
updateRootChunksStructure(i + 1); updateRootChunksStructure(i + 1);
} }
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data) { void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data) {
if (d->chunks.size() == 0) { if (d->chunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found."); debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return; return;
@@ -387,9 +411,11 @@ void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &da
chunk.padding = (data.size() & 0x01) ? 1 : 0; chunk.padding = (data.size() & 0x01) ? 1 : 0;
d->chunks.push_back(chunk); d->chunks.push_back(chunk);
} }
void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum) { void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum) {
ChunkList &childChunks = d->childChunks[childChunkNum]; ChunkList &childChunks = d->childChunks[childChunkNum];
// Update global size // Update global size
@@ -424,11 +450,11 @@ void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum)
d->chunks[i].offset = d->chunks[i - 1].offset + 12 + d->chunks[i - 1].size + d->chunks[i - 1].padding; d->chunks[i].offset = d->chunks[i - 1].offset + 12 + d->chunks[i - 1].size + d->chunks[i - 1].padding;
childChunks.erase(childChunks.begin() + i); childChunks.erase(childChunks.begin() + i);
} }
void DSDIFF::File::setChildChunkData(unsigned int i, void DSDIFF::File::setChildChunkData(unsigned int i, const ByteVector &data, unsigned int childChunkNum) {
const ByteVector &data,
unsigned int childChunkNum) {
ChunkList &childChunks = d->childChunks[childChunkNum]; ChunkList &childChunks = d->childChunks[childChunkNum];
if (data.isEmpty()) { if (data.isEmpty()) {
@@ -445,11 +471,8 @@ void DSDIFF::File::setChildChunkData(unsigned int i,
// And the PROP chunk size // And the PROP chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += d->chunks[d->childChunkIndex[childChunkNum]].size += ((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding);
((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding); insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size, d->endianness == BigEndian), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now update the specific chunk // Now update the specific chunk
@@ -468,11 +491,11 @@ void DSDIFF::File::setChildChunkData(unsigned int i,
// And for root chunks // And for root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1); updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
} }
void DSDIFF::File::setChildChunkData(const ByteVector &name, void DSDIFF::File::setChildChunkData(const ByteVector &name, const ByteVector &data, unsigned int childChunkNum) {
const ByteVector &data,
unsigned int childChunkNum) {
ChunkList &childChunks = d->childChunks[childChunkNum]; ChunkList &childChunks = d->childChunks[childChunkNum];
if (childChunks.size() == 0) { if (childChunks.size() == 0) {
@@ -530,9 +553,11 @@ void DSDIFF::File::setChildChunkData(const ByteVector &name,
chunk.padding = (data.size() & 0x01) ? 1 : 0; chunk.padding = (data.size() & 0x01) ? 1 : 0;
childChunks.push_back(chunk); childChunks.push_back(chunk);
} }
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk) { void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk) {
for (unsigned int i = startingChunk; i < d->chunks.size(); i++) for (unsigned int i = startingChunk; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12 + d->chunks[i - 1].size + d->chunks[i - 1].padding; d->chunks[i].offset = d->chunks[i - 1].offset + 12 + d->chunks[i - 1].size + d->chunks[i - 1].padding;
@@ -554,9 +579,11 @@ void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk) {
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12 + childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding; childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12 + childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
} }
} }
} }
void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) {
bool bigEndian = (d->endianness == BigEndian); bool bigEndian = (d->endianness == BigEndian);
d->type = readBlock(4); d->type = readBlock(4);
@@ -856,11 +883,11 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
d->isID3InPropChunk = false; d->isID3InPropChunk = false;
d->hasID3v2 = false; d->hasID3v2 = false;
} }
} }
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, unsigned long long offset, unsigned long replace, unsigned int leadingPadding) {
unsigned long long offset, unsigned long replace,
unsigned int leadingPadding) {
ByteVector combined; ByteVector combined;
if (leadingPadding) if (leadingPadding)
combined.append(ByteVector(leadingPadding, '\x00')); combined.append(ByteVector(leadingPadding, '\x00'));
@@ -872,4 +899,5 @@ void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
combined.append('\x00'); combined.append('\x00');
insert(combined, offset, replace); insert(combined, offset, replace);
} }

View File

@@ -37,34 +37,32 @@ namespace TagLib {
//! An implementation of DSDIFF metadata //! An implementation of DSDIFF metadata
/*! /*!
* This is implementation of DSDIFF metadata. * This is implementation of DSDIFF metadata.
* *
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF * This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
* chunk as well as properties from the file. * chunk as well as properties from the file.
* Description of the DSDIFF format is available * Description of the DSDIFF format is available at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
* at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf * DSDIFF standard does not explicitly specify the ID3V2 chunk
* DSDIFF standard does not explicitly specify the ID3V2 chunk * It can be found at the root level, but also sometimes inside the PROP chunk.
* It can be found at the root level, but also sometimes inside the PROP chunk * In addition, title and artist info are stored as part of the standard
* In addition, title and artist info are stored as part of the standard */
*/
namespace DSDIFF { namespace DSDIFF {
//! An implementation of TagLib::File with DSDIFF specific methods //! An implementation of TagLib::File with DSDIFF specific methods
/*! /*!
* This implements and provides an interface for DSDIFF files to the * This implements and provides an interface for DSDIFF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing the
* the abstract TagLib::File API as well as providing some additional * abstract TagLib::File API as well as providing some additional information specific to DSDIFF files.
* information specific to DSDIFF files. */
*/
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* This set of flags is used for various operations and is suitable for * This set of flags is used for various operations and is suitable for
* being OR-ed together. * being OR-ed together.
*/ */
enum TagTypes { enum TagTypes {
//! Empty set. Matches no tag types. //! Empty set. Matches no tag types.
NoTags = 0x0000, NoTags = 0x0000,
@@ -77,147 +75,136 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
}; };
/*! /*!
* Constructs an DSDIFF file from \a file. If \a readProperties is true * Constructs an DSDIFF file from \a file.
* the file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * \note In the current implementation, \a propertiesStyle is ignored.
*/ */
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs an DSDIFF file from \a stream. If \a readProperties is true * Constructs an DSDIFF file from \a stream.
* the file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note TagLib will *not* take ownership of the stream, the caller is * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
* responsible for deleting it after the File object. *
* * \note In the current implementation, \a propertiesStyle is ignored.
* \note In the current implementation, \a propertiesStyle is ignored. */
*/
File(IOStream *stream, bool readProperties = true, File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average); Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
/*! /*!
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN * Returns a pointer to a tag that is the union of the ID3v2 and DIIN tags.
* tags. The ID3v2 tag is given priority in reading the information -- if * The ID3v2 tag is given priority in reading the information -- if requested information exists in both the ID3v2 tag and the ID3v1 tag,
* requested information exists in both the ID3v2 tag and the ID3v1 tag, * the information from the ID3v2 tag will be returned.
* the information from the ID3v2 tag will be returned. *
* * If you would like more granular control over the content of the tags, with the concession of generality, use the tag-type specific calls.
* If you would like more granular control over the content of the tags, *
* with the concession of generality, use the tag-type specific calls. * \note As this tag is not implemented as an ID3v2 tag or a DIIN tag,
* * but a union of the two this pointer may not be cast to the specific tag types.
* \note As this tag is not implemented as an ID3v2 tag or a DIIN tag, *
* but a union of the two this pointer may not be cast to the specific * \see ID3v2Tag()
* tag types. * \see DIINTag()
* */
* \see ID3v2Tag()
* \see DIINTag()
*/
virtual Tag *tag() const; virtual Tag *tag() const;
/*! /*!
* Returns the ID3V2 Tag for this file. * Returns the ID3V2 Tag for this file.
* *
* \note This always returns a valid pointer regardless of whether or not * \note This always returns a valid pointer regardless of whether or not the file on disk has an ID3v2 tag.
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the * Use hasID3v2Tag() to check if the file on disk actually has an ID3v2 tag.
* file on disk actually has an ID3v2 tag. *
* * \see hasID3v2Tag()
* \see hasID3v2Tag() */
*/
ID3v2::Tag *ID3v2Tag(bool create = false) const; ID3v2::Tag *ID3v2Tag(bool create = false) const;
/*! /*!
* Returns the DSDIFF DIIN Tag for this file * Returns the DSDIFF DIIN Tag for this file
* *
*/ */
DSDIFF::DIIN::Tag *DIINTag(bool create = false) const; DSDIFF::DIIN::Tag *DIINTag(bool create = false) const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties(). * This method forwards to ID3v2::Tag::properties().
*/ */
PropertyMap properties() const; PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties); void removeUnsupportedProperties(const StringList &properties);
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties(). * This method forwards to ID3v2::Tag::setProperties().
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the AIFF::Properties for this file. If no audio properties * Returns the AIFF::Properties for this file.
* were read then this will return a null pointer. * If no audio properties were read then this will return a null pointer.
*/ */
virtual Properties *audioProperties() const; virtual Properties *audioProperties() const;
/*! /*!
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this * Save the file. If at least one tag -- ID3v1 or DIIN -- exists this will duplicate its content into the other tag.
* will duplicate its content into the other tag. This returns true * This returns true if saving was successful.
* if saving was successful. *
* * If neither exists or if both tags are empty, this will strip the tags from the file.
* If neither exists or if both tags are empty, this will strip the tags *
* from the file. * This is the same as calling save(AllTags);
* *
* This is the same as calling save(AllTags); * If you would like more granular control over the content of the tags,
* * with the concession of generality, use paramaterized save call below.
* If you would like more granular control over the content of the tags, *
* with the concession of generality, use paramaterized save call below. * \see save(int tags)
* */
* \see save(int tags)
*/
virtual bool save(); virtual bool save();
/*! /*!
* Save the file. If \a strip is specified, it is possible to choose if * Save the file. If \a strip is specified,
* tags not specified in \a tags should be stripped from the file or * it is possible to choose if tags not specified in \a tags should be stripped from the file or retained.
* retained. With \a version, it is possible to specify whether ID3v2.4 * With \a version, it is possible to specify whether ID3v2.4 or ID3v2.3 should be used.
* or ID3v2.3 should be used. */
*/
bool save(TagTypes tags, StripTags strip = StripOthers, ID3v2::Version version = ID3v2::v4); bool save(TagTypes tags, StripTags strip = StripOthers, ID3v2::Version version = ID3v2::v4);
/*! /*!
* This will strip the tags that match the OR-ed together TagTypes from the * This will strip the tags that match the OR-ed together TagTypes from the file.
* file. By default it strips all tags. It returns true if the tags are * By default it strips all tags. It returns true if the tags are successfully stripped.
* successfully stripped. *
* * \note This will update the file immediately.
* \note This will update the file immediately. */
*/
void strip(TagTypes tags = AllTags); void strip(TagTypes tags = AllTags);
/*! /*!
* Returns whether or not the file on disk actually has an ID3v2 tag. * Returns whether or not the file on disk actually has an ID3v2 tag.
* *
* \see ID3v2Tag() * \see ID3v2Tag()
*/ */
bool hasID3v2Tag() const; bool hasID3v2Tag() const;
/*! /*!
* Returns whether or not the file on disk actually has the DSDIFF * Returns whether or not the file on disk actually has the DSDIFF title and artist tags.
* title and artist tags. *
* * \see DIINTag()
* \see DIINTag() */
*/
bool hasDIINTag() const; bool hasDIINTag() const;
/*! /*!
* Returns whether or not the given \a stream can be opened as a DSDIFF * Returns whether or not the given \a stream can be opened as a DSDIFF file.
* file. *
* * \note This method is designed to do a quick check. The result may not necessarily be correct.
* \note This method is designed to do a quick check. The result may */
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
protected: protected:
enum Endianness { BigEndian, enum Endianness {
LittleEndian }; BigEndian,
LittleEndian
};
File(FileName file, Endianness endianness); File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness); File(IOStream *stream, Endianness endianness);
@@ -231,50 +218,44 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
void removeChildChunk(unsigned int i, unsigned int chunk); void removeChildChunk(unsigned int i, unsigned int chunk);
/*! /*!
* Sets the data for the the specified chunk at root level to \a data. * Sets the data for the the specified chunk at root level to \a data.
* *
* \warning This will update the file immediately. * \warning This will update the file immediately.
*/ */
void setRootChunkData(unsigned int i, const ByteVector &data); void setRootChunkData(unsigned int i, const ByteVector &data);
/*! /*!
* Sets the data for the root-level chunk \a name to \a data. * Sets the data for the root-level chunk \a name to \a data.
* If a root-level chunk with the given name already exists * If a root-level chunk with the given name already exists it will be overwritten, otherwise it will be created after the existing chunks.
* it will be overwritten, otherwise it will be *
* created after the existing chunks. * \warning This will update the file immediately.
* */
* \warning This will update the file immediately.
*/
void setRootChunkData(const ByteVector &name, const ByteVector &data); void setRootChunkData(const ByteVector &name, const ByteVector &data);
/*! /*!
* Sets the data for the the specified child chunk to \a data. * Sets the data for the the specified child chunk to \a data.
* *
* If data is null, then remove the chunk * If data is null, then remove the chunk
* *
* \warning This will update the file immediately. * \warning This will update the file immediately.
*/ */
void setChildChunkData(unsigned int i, const ByteVector &data, void setChildChunkData(unsigned int i, const ByteVector &data, unsigned int childChunkNum);
unsigned int childChunkNum);
/*! /*!
* Sets the data for the child chunk \a name to \a data. If a chunk with * Sets the data for the child chunk \a name to \a data.
* the given name already exists it will be overwritten, otherwise it will * If a chunk with the given name already exists it will be overwritten, otherwise it will be created after the existing chunks inside child chunk.
* be created after the existing chunks inside child chunk. *
* * If data is null, then remove the chunks with \a name name
* If data is null, then remove the chunks with \a name name *
* * \warning This will update the file immediately.
* \warning This will update the file immediately. */
*/
void setChildChunkData(const ByteVector &name, const ByteVector &data, void setChildChunkData(const ByteVector &name, const ByteVector &data,
unsigned int childChunkNum); unsigned int childChunkNum);
void updateRootChunksStructure(unsigned int startingChunk); void updateRootChunksStructure(unsigned int startingChunk);
void read(bool readProperties, Properties::ReadStyle propertiesStyle); void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void writeChunk(const ByteVector &name, const ByteVector &data, void writeChunk(const ByteVector &name, const ByteVector &data, unsigned long long offset, unsigned long replace = 0, unsigned int leadingPadding = 0);
unsigned long long offset, unsigned long replace = 0,
unsigned int leadingPadding = 0);
class FilePrivate; class FilePrivate;
FilePrivate *d; FilePrivate *d;

View File

@@ -52,11 +52,8 @@ class DSDIFF::Properties::PropertiesPrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DSDIFF::Properties::Properties(const unsigned int sampleRate, DSDIFF::Properties::Properties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle style) : AudioProperties(style) {
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) : AudioProperties(style) {
d = new PropertiesPrivate; d = new PropertiesPrivate;
d->channels = channels; d->channels = channels;
@@ -65,6 +62,7 @@ DSDIFF::Properties::Properties(const unsigned int sampleRate,
d->sampleRate = sampleRate; d->sampleRate = sampleRate;
d->bitrate = bitrate; d->bitrate = bitrate;
d->length = d->sampleRate > 0 ? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5) : 0; d->length = d->sampleRate > 0 ? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5) : 0;
} }
DSDIFF::Properties::~Properties() { DSDIFF::Properties::~Properties() {

View File

@@ -30,7 +30,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace DSDIFF { namespace DSDIFF {
class File; class File;
@@ -38,23 +37,19 @@ class File;
//! An implementation of audio property reading for DSDIFF //! An implementation of audio property reading for DSDIFF
/*! /*!
* This reads the data from an DSDIFF stream found in the AudioProperties * This reads the data from an DSDIFF stream found in the AudioProperties API.
* API. */
*/
class TAGLIB_EXPORT Properties : public AudioProperties { class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperties {
public: public:
/*! /*!
* Create an instance of DSDIFF::Properties with the data read from the * Create an instance of DSDIFF::Properties with the data read from the ByteVector \a data.
* ByteVector \a data. */
*/ Properties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle style);
Properties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
/*! /*!
* Destroys this DSDIFF::Properties instance. * Destroys this DSDIFF::Properties instance.
*/ */
virtual ~Properties(); virtual ~Properties();
// Reimplementations. // Reimplementations.
@@ -76,6 +71,7 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
class PropertiesPrivate; class PropertiesPrivate;
PropertiesPrivate *d; PropertiesPrivate *d;
}; };
} // namespace DSDIFF } // namespace DSDIFF
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -60,9 +60,11 @@ class DSF::File::FilePrivate {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool DSF::File::isSupported(IOStream *stream) { bool DSF::File::isSupported(IOStream *stream) {
// A DSF file has to start with "DSD " // A DSF file has to start with "DSD "
const ByteVector id = Utils::readHeader(stream, 4, false); const ByteVector id = Utils::readHeader(stream, 4, false);
return id.startsWith("DSD "); return id.startsWith("DSD ");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -70,17 +72,18 @@ bool DSF::File::isSupported(IOStream *stream) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DSF::File::File(FileName file, bool readProperties, DSF::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file), Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties, propertiesStyle); read(readProperties, propertiesStyle);
} }
DSF::File::File(IOStream *stream, bool readProperties, DSF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream),
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties, propertiesStyle); read(readProperties, propertiesStyle);
} }
DSF::File::~File() { DSF::File::~File() {
@@ -104,6 +107,7 @@ DSF::Properties *DSF::File::audioProperties() const {
} }
bool DSF::File::save() { bool DSF::File::save() {
if (readOnly()) { if (readOnly()) {
debug("DSF::File::save() -- File is read only."); debug("DSF::File::save() -- File is read only.");
return false; return false;
@@ -158,6 +162,7 @@ bool DSF::File::save() {
} }
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -166,6 +171,7 @@ bool DSF::File::save() {
void DSF::File::read(bool, Properties::ReadStyle propertiesStyle) { void DSF::File::read(bool, Properties::ReadStyle propertiesStyle) {
// A DSF file consists of four chunks: DSD chunk, format chunk, data chunk, and metadata chunk // A DSF file consists of four chunks: DSD chunk, format chunk, data chunk, and metadata chunk
// The file format is not chunked in the sense of a RIFF File, though // The file format is not chunked in the sense of a RIFF File, though
@@ -223,4 +229,5 @@ void DSF::File::read(bool, Properties::ReadStyle propertiesStyle) {
d->tag = new ID3v2::Tag(); d->tag = new ID3v2::Tag();
else else
d->tag = new ID3v2::Tag(this, d->metadataOffset); d->tag = new ID3v2::Tag(this, d->metadataOffset);
} }

View File

@@ -36,80 +36,79 @@ namespace TagLib {
//! An implementation of DSF metadata //! An implementation of DSF metadata
/*! /*!
* This is implementation of DSF metadata. * This is implementation of DSF metadata.
* *
* This supports an ID3v2 tag as well as properties from the file. * This supports an ID3v2 tag as well as properties from the file.
*/ */
namespace DSF { namespace DSF {
//! An implementation of Strawberry_TagLib::TagLib::File with DSF specific methods //! An implementation of Strawberry_TagLib::TagLib::File with DSF specific methods
/*! /*!
* This implements and provides an interface for DSF files to the * This implements and provides an interface for DSF files to the
* Strawberry_TagLib::TagLib::Tag and Strawberry_TagLib::TagLib::AudioProperties interfaces by way of implementing * Strawberry_TagLib::TagLib::Tag and Strawberry_TagLib::TagLib::AudioProperties interfaces by way of implementing
* the abstract Strawberry_TagLib::TagLib::File API as well as providing some additional * the abstract Strawberry_TagLib::TagLib::File API as well as providing some additional information specific to DSF files.
* information specific to DSF files. *
*/ */
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* Constructs an DSF file from \a file. If \a readProperties is true the * Constructs an DSF file from \a file.
* file's audio properties will also be read using \a propertiesStyle. If * If \a readProperties is true the file's audio properties will also be read using \a propertiesStyle.
* false, \a propertiesStyle is ignored. * If false, \a propertiesStyle is ignored.
*/ */
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average); Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs an DSF file from \a file. If \a readProperties is true the * Constructs an DSF file from \a file.
* file's audio properties will also be read using \a propertiesStyle. If * If \a readProperties is true the file's audio properties will also be read using \a propertiesStyle.
* false, \a propertiesStyle is ignored. * If false, \a propertiesStyle is ignored.
*/ */
File(IOStream *stream, bool readProperties = true, File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average); Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
/*! /*!
* Returns the Tag for this file. * Returns the Tag for this file.
*/ */
ID3v2::Tag *tag() const; ID3v2::Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties(). * This method forwards to ID3v2::Tag::properties().
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties(). * This method forwards to ID3v2::Tag::setProperties().
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the DSF::AudioProperties for this file. If no audio properties * Returns the DSF::AudioProperties for this file.
* were read then this will return a null pointer. * If no audio properties were read then this will return a null pointer.
*/ */
virtual Properties *audioProperties() const; virtual Properties *audioProperties() const;
/*! /*!
* Saves the file. * Saves the file.
*/ */
virtual bool save(); virtual bool save();
/*! /*!
* Returns whether or not the given \a stream can be opened as a DSF * Returns whether or not the given \a stream can be opened as a DSF file.
* file. *
* * \note This method is designed to do a quick check.
* \note This method is designed to do a quick check. The result may * The result may not necessarily be correct.
* not necessarily be correct. */
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
private: private:

View File

@@ -30,7 +30,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace DSF { namespace DSF {
class File; class File;
@@ -38,21 +37,19 @@ class File;
//! An implementation of audio property reading for DSF //! An implementation of audio property reading for DSF
/*! /*!
* This reads the data from a DSF stream found in the AudioProperties * This reads the data from a DSF stream found in the AudioProperties API.
* API. */
*/
class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperties { class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperties {
public: public:
/*! /*!
* Create an instance of DSF::AudioProperties with the data read from the * Create an instance of DSF::AudioProperties with the data read from the ByteVector \a data.
* ByteVector \a data. */
*/
Properties(const ByteVector &data, ReadStyle style); Properties(const ByteVector &data, ReadStyle style);
/*! /*!
* Destroys this DSF::AudioProperties instance. * Destroys this DSF::AudioProperties instance.
*/ */
virtual ~Properties(); virtual ~Properties();
// Reimplementations. // Reimplementations.
@@ -68,9 +65,15 @@ class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperti
int formatID() const; int formatID() const;
/*! /*!
* Channel type values: 1 = mono, 2 = stereo, 3 = 3 channels, * Channel type values:
* 4 = quad, 5 = 4 channels, 6 = 5 channels, 7 = 5.1 channels * 1 = mono,
*/ * 2 = stereo,
* 3 = 3 channels,
* 4 = quad,
* 5 = 4 channels,
* 6 = 5 channels,
* 7 = 5.1 channels
*/
int channelType() const; int channelType() const;
int bitsPerSample() const; int bitsPerSample() const;
long long sampleCount() const; long long sampleCount() const;

View File

@@ -63,8 +63,8 @@ ResolverList fileTypeResolvers;
// Detect the file type by user-defined resolvers. // Detect the file type by user-defined resolvers.
File *detectByResolvers(FileName fileName, bool readAudioProperties, File *detectByResolvers(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
AudioProperties::ReadStyle audioPropertiesStyle) {
ResolverList::ConstIterator it = fileTypeResolvers.begin(); ResolverList::ConstIterator it = fileTypeResolvers.begin();
for (; it != fileTypeResolvers.end(); ++it) { for (; it != fileTypeResolvers.end(); ++it) {
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
@@ -73,12 +73,13 @@ File *detectByResolvers(FileName fileName, bool readAudioProperties,
} }
return nullptr; return nullptr;
} }
// Detect the file type based on the file extension. // Detect the file type based on the file extension.
File *detectByExtension(IOStream *stream, bool readAudioProperties, File *detectByExtension(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
AudioProperties::ReadStyle audioPropertiesStyle) {
#ifdef _WIN32 #ifdef _WIN32
const String s = stream->name().toString(); const String s = stream->name().toString();
#else #else
@@ -140,13 +141,14 @@ File *detectByExtension(IOStream *stream, bool readAudioProperties,
return new DSF::File(stream, readAudioProperties, audioPropertiesStyle); return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
return nullptr; return nullptr;
} }
// Detect the file type based on the actual content of the stream. // Detect the file type based on the actual content of the stream.
File *detectByContent(IOStream *stream, bool readAudioProperties, File *detectByContent(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
AudioProperties::ReadStyle audioPropertiesStyle) {
File *file = 0; File *file = nullptr;
if (MPEG::File::isSupported(stream)) if (MPEG::File::isSupported(stream))
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
@@ -191,17 +193,17 @@ File *detectByContent(IOStream *stream, bool readAudioProperties,
} }
return nullptr; return nullptr;
} }
// Internal function that supports FileRef::create(). // Internal function that supports FileRef::create().
// This looks redundant, but necessary in order not to change the previous // This looks redundant, but necessary in order not to change the previous
// behavior of FileRef::create(). // behavior of FileRef::create().
File *createInternal(FileName fileName, bool readAudioProperties, File *createInternal(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
AudioProperties::ReadStyle audioPropertiesStyle) {
File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
if (file) if (file) return file;
return file;
#ifdef _WIN32 #ifdef _WIN32
const String s = fileName.toString(); const String s = fileName.toString();
@@ -266,14 +268,13 @@ File *createInternal(FileName fileName, bool readAudioProperties,
return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle); return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle);
return nullptr; return nullptr;
} }
} // namespace } // namespace
class FileRef::FileRefPrivate : public RefCounter { class FileRef::FileRefPrivate : public RefCounter {
public: public:
FileRefPrivate() : RefCounter(), FileRefPrivate() : RefCounter(), file(nullptr), stream(nullptr) {}
file(0),
stream(0) {}
~FileRefPrivate() { ~FileRefPrivate() {
delete file; delete file;
@@ -288,11 +289,9 @@ class FileRef::FileRefPrivate : public RefCounter {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
FileRef::FileRef() : d(new FileRefPrivate()) { FileRef::FileRef() : d(new FileRefPrivate()) {}
}
FileRef::FileRef(FileName fileName, bool readAudioProperties, FileRef::FileRef(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : d(new FileRefPrivate()) {
AudioProperties::ReadStyle audioPropertiesStyle) : d(new FileRefPrivate()) {
parse(fileName, readAudioProperties, audioPropertiesStyle); parse(fileName, readAudioProperties, audioPropertiesStyle);
} }
@@ -309,24 +308,30 @@ FileRef::FileRef(const FileRef &ref) : d(ref.d) {
} }
FileRef::~FileRef() { FileRef::~FileRef() {
if (d->deref()) if (d->deref())
delete d; delete d;
} }
Tag *FileRef::tag() const { Tag *FileRef::tag() const {
if (isNull()) { if (isNull()) {
debug("FileRef::tag() - Called without a valid file."); debug("FileRef::tag() - Called without a valid file.");
return nullptr; return nullptr;
} }
return d->file->tag(); return d->file->tag();
} }
AudioProperties *FileRef::audioProperties() const { AudioProperties *FileRef::audioProperties() const {
if (isNull()) { if (isNull()) {
debug("FileRef::audioProperties() - Called without a valid file."); debug("FileRef::audioProperties() - Called without a valid file.");
return nullptr; return nullptr;
} }
return d->file->audioProperties(); return d->file->audioProperties();
} }
File *FileRef::file() const { File *FileRef::file() const {
@@ -334,20 +339,22 @@ File *FileRef::file() const {
} }
bool FileRef::save() { bool FileRef::save() {
if (isNull()) { if (isNull()) {
debug("FileRef::save() - Called without a valid file."); debug("FileRef::save() - Called without a valid file.");
return false; return false;
} }
return d->file->save(); return d->file->save();
} }
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) { // static
{
fileTypeResolvers.prepend(resolver); fileTypeResolvers.prepend(resolver);
return resolver; return resolver;
} }
StringList FileRef::defaultFileExtensions() { StringList FileRef::defaultFileExtensions() {
StringList l; StringList l;
l.append("ogg"); l.append("ogg");
@@ -383,6 +390,7 @@ StringList FileRef::defaultFileExtensions() {
l.append("dsdiff"); // alias for "dff" l.append("dsdiff"); // alias for "dff"
return l; return l;
} }
bool FileRef::isNull() const { bool FileRef::isNull() const {
@@ -408,9 +416,7 @@ bool FileRef::operator!=(const FileRef &ref) const {
return (ref.d->file != d->file); return (ref.d->file != d->file);
} }
File *FileRef::create(FileName fileName, bool readAudioProperties, File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { // static
AudioProperties::ReadStyle audioPropertiesStyle) // static
{
return createInternal(fileName, readAudioProperties, audioPropertiesStyle); return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
} }
@@ -418,8 +424,8 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void FileRef::parse(FileName fileName, bool readAudioProperties, void FileRef::parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
AudioProperties::ReadStyle audioPropertiesStyle) {
// Try user-defined resolvers. // Try user-defined resolvers.
d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
@@ -442,11 +448,12 @@ void FileRef::parse(FileName fileName, bool readAudioProperties,
// Stream have to be closed here if failed to resolve file types. // Stream have to be closed here if failed to resolve file types.
delete d->stream; delete d->stream;
d->stream = 0; d->stream = nullptr;
} }
void FileRef::parse(IOStream *stream, bool readAudioProperties, void FileRef::parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
AudioProperties::ReadStyle audioPropertiesStyle) {
// User-defined resolvers won't work with a stream. // User-defined resolvers won't work with a stream.
// Try to resolve file types based on the file extension. // Try to resolve file types based on the file extension.
@@ -458,4 +465,5 @@ void FileRef::parse(IOStream *stream, bool readAudioProperties,
// At last, try to resolve file types based on the actual content of the file. // At last, try to resolve file types based on the actual content of the file.
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle); d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
} }

View File

@@ -40,18 +40,15 @@ class Tag;
//! This class provides a simple abstraction for creating and handling files //! This class provides a simple abstraction for creating and handling files
/*! /*!
* FileRef exists to provide a minimal, generic and value-based wrapper around * FileRef exists to provide a minimal, generic and value-based wrapper around a File.
* a File. It is lightweight and implicitly shared, and as such suitable for * It is lightweight and implicitly shared, and as such suitable for pass-by-value use.
* pass-by-value use. This hides some of the uglier details of TagLib::File * This hides some of the uglier details of TagLib::File and the non-generic portions of the concrete file implementations.
* and the non-generic portions of the concrete file implementations.
* *
* This class is useful in a "simple usage" situation where it is desirable * This class is useful in a "simple usage" situation where it is desirable
* to be able to get and set some of the tag information that is similar * to be able to get and set some of the tag information that is similar across file types.
* across file types.
* *
* Also note that it is probably a good idea to plug this into your mime * Also note that it is probably a good idea to plug this into your mime
* type system rather than using the constructor that accepts a file name using * type system rather than using the constructor that accepts a file name using the FileTypeResolver.
* the FileTypeResolver.
* *
* \see FileTypeResolver * \see FileTypeResolver
* \see addFileTypeResolver() * \see addFileTypeResolver()
@@ -62,8 +59,7 @@ class TAGLIB_EXPORT FileRef {
//! A class for pluggable file type resolution. //! A class for pluggable file type resolution.
/*! /*!
* This class is used to add extend TagLib's very basic file name based file * This class is used to add extend TagLib's very basic file name based file type resolution.
* type resolution.
* *
* This can be accomplished with: * This can be accomplished with:
* *
@@ -83,191 +79,177 @@ class TAGLIB_EXPORT FileRef {
* *
* \endcode * \endcode
* *
* Naturally a less contrived example would be slightly more complex. This * Naturally a less contrived example would be slightly more complex.
* can be used to plug in mime-type detection systems or to add new file types * This can be used to plug in mime-type detection systems or to add new file types to TagLib.
* to TagLib.
*/ */
class TAGLIB_EXPORT FileTypeResolver { class TAGLIB_EXPORT FileTypeResolver {
public: public:
virtual ~FileTypeResolver(); virtual ~FileTypeResolver();
/*! /*!
* This method must be overridden to provide an additional file type * This method must be overridden to provide an additional file type resolver.
* resolver. If the resolver is able to determine the file type it should * If the resolver is able to determine the file type it should return a valid File object; if not it should return 0.
* return a valid File object; if not it should return 0. *
* * \note The created file is then owned by the FileRef and should not be deleted.
* \note The created file is then owned by the FileRef and should not be * Deletion will happen automatically when the FileRef passes out of scope.
* deleted. Deletion will happen automatically when the FileRef passes */
* out of scope.
*/
virtual File *createFile(FileName fileName, virtual File *createFile(FileName fileName,
bool readAudioProperties = true, bool readAudioProperties = true,
AudioProperties::ReadStyle AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0;
audioPropertiesStyle = AudioProperties::Average) const = 0;
}; };
/*! /*!
* Creates a null FileRef. * Creates a null FileRef.
*/ */
FileRef(); FileRef();
/*! /*!
* Create a FileRef from \a fileName. If \a readAudioProperties is true then * Create a FileRef from \a fileName.
* the audio properties will be read using \a audioPropertiesStyle. If * If \a readAudioProperties is true then the audio properties will be read using \a audioPropertiesStyle.
* \a readAudioProperties is false then \a audioPropertiesStyle will be * If \a readAudioProperties is false then \a audioPropertiesStyle will be ignored.
* ignored. *
* * Also see the note in the class documentation about why you may not want to
* Also see the note in the class documentation about why you may not want to * use this method in your application.
* use this method in your application. */
*/
explicit FileRef(FileName fileName, explicit FileRef(FileName fileName,
bool readAudioProperties = true, bool readAudioProperties = true,
AudioProperties::ReadStyle AudioProperties::ReadStyle
audioPropertiesStyle = AudioProperties::Average); audioPropertiesStyle = AudioProperties::Average);
/*! /*!
* Construct a FileRef from an opened \a IOStream. If \a readAudioProperties * Construct a FileRef from an opened \a IOStream.
* is true then the audio properties will be read using \a audioPropertiesStyle. * If \a readAudioProperties is true then the audio properties will be read using \a audioPropertiesStyle.
* If \a readAudioProperties is false then \a audioPropertiesStyle will be * If \a readAudioProperties is false then \a audioPropertiesStyle will be ignored.
* ignored. *
* * Also see the note in the class documentation about why you may not want to use this method in your application.
* Also see the note in the class documentation about why you may not want to *
* use this method in your application. * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
* */
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
explicit FileRef(IOStream *stream, explicit FileRef(IOStream *stream,
bool readAudioProperties = true, bool readAudioProperties = true,
AudioProperties::ReadStyle AudioProperties::ReadStyle
audioPropertiesStyle = AudioProperties::Average); audioPropertiesStyle = AudioProperties::Average);
/*! /*!
* Construct a FileRef using \a file. The FileRef now takes ownership of the * Construct a FileRef using \a file.
* pointer and will delete the File when it passes out of scope. * The FileRef now takes ownership of the pointer and will delete the File when it passes out of scope.
*/ */
explicit FileRef(File *file); explicit FileRef(File *file);
/*! /*!
* Make a copy of \a ref. * Make a copy of \a ref.
*/ */
FileRef(const FileRef &ref); FileRef(const FileRef &ref);
/*! /*!
* Destroys this FileRef instance. * Destroys this FileRef instance.
*/ */
virtual ~FileRef(); virtual ~FileRef();
/*! /*!
* Returns a pointer to represented file's tag. * Returns a pointer to represented file's tag.
* *
* \warning This pointer will become invalid when this FileRef and all * \warning This pointer will become invalid when this FileRef and all
* copies pass out of scope. * copies pass out of scope.
* *
* \warning Do not cast it to any subclasses of \class Tag. * \warning Do not cast it to any subclasses of \class Tag.
* Use tag returning methods of appropriate subclasses of \class File instead. * Use tag returning methods of appropriate subclasses of \class File instead.
* *
* \see File::tag() * \see File::tag()
*/ */
Tag *tag() const; Tag *tag() const;
/*! /*!
* Returns the audio properties for this FileRef. If no audio properties * Returns the audio properties for this FileRef.
* were read then this will returns a null pointer. * If no audio properties were read then this will returns a null pointer.
*/ */
AudioProperties *audioProperties() const; AudioProperties *audioProperties() const;
/*! /*!
* Returns a pointer to the file represented by this handler class. * Returns a pointer to the file represented by this handler class.
* *
* As a general rule this call should be avoided since if you need to work * As a general rule this call should be avoided since if you need to work
* with file objects directly, you are probably better served instantiating * with file objects directly, you are probably better served instantiating
* the File subclasses (i.e. MPEG::File) manually and working with their APIs. * the File subclasses (i.e. MPEG::File) manually and working with their APIs.
* *
* This <i>handle</i> exists to provide a minimal, generic and value-based * This <i>handle</i> exists to provide a minimal, generic and value-based
* wrapper around a File. Accessing the file directly generally indicates * wrapper around a File. Accessing the file directly generally indicates
* a moving away from this simplicity (and into things beyond the scope of * a moving away from this simplicity (and into things beyond the scope of
* FileRef). * FileRef).
* *
* \warning This pointer will become invalid when this FileRef and all * \warning This pointer will become invalid when this FileRef and all
* copies pass out of scope. * copies pass out of scope.
*/ */
File *file() const; File *file() const;
/*! /*!
* Saves the file. Returns true on success. * Saves the file. Returns true on success.
*/ */
bool save(); bool save();
/*! /*!
* Adds a FileTypeResolver to the list of those used by TagLib. Each * Adds a FileTypeResolver to the list of those used by TagLib.
* additional FileTypeResolver is added to the front of a list of resolvers * Each additional FileTypeResolver is added to the front of a list of resolvers that are tried.
* that are tried. If the FileTypeResolver returns zero the next resolver * If the FileTypeResolver returns zero the next resolver is tried.
* is tried. *
* * Returns a pointer to the added resolver (the same one that's passed in --
* Returns a pointer to the added resolver (the same one that's passed in -- * this is mostly so that static initializers have something to use for assignment).
* this is mostly so that static initializers have something to use for *
* assignment). * \see FileTypeResolver
* */
* \see FileTypeResolver
*/
static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver); static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
/*! /*!
* As is mentioned elsewhere in this class's documentation, the default file * As is mentioned elsewhere in this class's documentation, the default file
* type resolution code provided by TagLib only works by comparing file * type resolution code provided by TagLib only works by comparing file extensions.
* extensions. *
* * This method returns the list of file extensions that are used by default.
* This method returns the list of file extensions that are used by default. *
* * The extensions are all returned in lowercase, though the comparison used
* The extensions are all returned in lowercase, though the comparison used * by TagLib for resolution is case-insensitive.
* by TagLib for resolution is case-insensitive. *
* * \note This does not account for any additional file type resolvers that
* \note This does not account for any additional file type resolvers that * are plugged in. Also note that this is not intended to replace a proper
* are plugged in. Also note that this is not intended to replace a proper * mime-type resolution system, but is just here for reference.
* mime-type resolution system, but is just here for reference. *
* * \see FileTypeResolver
* \see FileTypeResolver */
*/
static StringList defaultFileExtensions(); static StringList defaultFileExtensions();
/*! /*!
* Returns true if the file (and as such other pointers) are null. * Returns true if the file (and as such other pointers) are null.
*/ */
bool isNull() const; bool isNull() const;
/*! /*!
* Assign the file pointed to by \a ref to this FileRef. * Assign the file pointed to by \a ref to this FileRef.
*/ */
FileRef &operator=(const FileRef &ref); FileRef &operator=(const FileRef &ref);
/*! /*!
* Exchanges the content of the FileRef by the content of \a ref. * Exchanges the content of the FileRef by the content of \a ref.
*/ */
void swap(FileRef &ref); void swap(FileRef &ref);
/*! /*!
* Returns true if this FileRef and \a ref point to the same File object. * Returns true if this FileRef and \a ref point to the same File object.
*/ */
bool operator==(const FileRef &ref) const; bool operator==(const FileRef &ref) const;
/*! /*!
* Returns true if this FileRef and \a ref do not point to the same File * Returns true if this FileRef and \a ref do not point to the same File object.
* object. */
*/
bool operator!=(const FileRef &ref) const; bool operator!=(const FileRef &ref) const;
/*! /*!
* A simple implementation of file type guessing. If \a readAudioProperties * A simple implementation of file type guessing.
* is true then the audio properties will be read using * If \a readAudioProperties is true then the audio properties will be read using \a audioPropertiesStyle.
* \a audioPropertiesStyle. If \a readAudioProperties is false then * If \a readAudioProperties is false then \a audioPropertiesStyle will be ignored.
* \a audioPropertiesStyle will be ignored. *
* * \note You generally shouldn't use this method, but instead the constructor directly.
* \note You generally shouldn't use this method, but instead the constructor *
* directly. * \deprecated
* */
* \deprecated
*/
static File *create(FileName fileName, static File *create(FileName fileName,
bool readAudioProperties = true, bool readAudioProperties = true,
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);

View File

@@ -64,7 +64,7 @@ class FLAC::File::FilePrivate {
ID3v2Location(-1), ID3v2Location(-1),
ID3v2OriginalSize(0), ID3v2OriginalSize(0),
ID3v1Location(-1), ID3v1Location(-1),
properties(0), properties(nullptr),
flacStart(0), flacStart(0),
streamStart(0), streamStart(0),
scanned(false) { scanned(false) {
@@ -97,34 +97,30 @@ class FLAC::File::FilePrivate {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool FLAC::File::isSupported(IOStream *stream) { bool FLAC::File::isSupported(IOStream *stream) {
// A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede. // A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede.
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
return (buffer.find("fLaC") >= 0); return (buffer.find("fLaC") >= 0);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(frameFactory)) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate(frameFactory)) {
bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
d(new FilePrivate(frameFactory)) {
if (isOpen())
read(readProperties);
}
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
d(new FilePrivate(frameFactory)) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
FLAC::File::~File() { FLAC::File::~File() {
@@ -152,6 +148,7 @@ FLAC::Properties *FLAC::File::audioProperties() const {
} }
bool FLAC::File::save() { bool FLAC::File::save() {
if (readOnly()) { if (readOnly()) {
debug("FLAC::File::save() - Cannot save to a read only file."); debug("FLAC::File::save() - Cannot save to a read only file.");
return false; return false;
@@ -288,6 +285,7 @@ bool FLAC::File::save() {
} }
return true; return true;
} }
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) { ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) {
@@ -302,21 +300,8 @@ Ogg::XiphComment *FLAC::File::xiphComment(bool create) {
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create); return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create);
} }
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) {
d->ID3v2FrameFactory = factory;
}
ByteVector FLAC::File::streamInfoData() {
debug("FLAC::File::streamInfoData() -- This function is obsolete. Returning an empty ByteVector.");
return ByteVector();
}
long FLAC::File::streamLength() {
debug("FLAC::File::streamLength() -- This function is obsolete. Returning zero.");
return 0;
}
List<FLAC::Picture *> FLAC::File::pictureList() { List<FLAC::Picture *> FLAC::File::pictureList() {
List<Picture *> pictures; List<Picture *> pictures;
for (BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { for (BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
Picture *picture = dynamic_cast<Picture *>(*it); Picture *picture = dynamic_cast<Picture *>(*it);
@@ -325,6 +310,7 @@ List<FLAC::Picture *> FLAC::File::pictureList() {
} }
} }
return pictures; return pictures;
} }
void FLAC::File::addPicture(Picture *picture) { void FLAC::File::addPicture(Picture *picture) {
@@ -332,15 +318,18 @@ void FLAC::File::addPicture(Picture *picture) {
} }
void FLAC::File::removePicture(Picture *picture, bool del) { void FLAC::File::removePicture(Picture *picture, bool del) {
BlockIterator it = d->blocks.find(picture); BlockIterator it = d->blocks.find(picture);
if (it != d->blocks.end()) if (it != d->blocks.end())
d->blocks.erase(it); d->blocks.erase(it);
if (del) if (del)
delete picture; delete picture;
} }
void FLAC::File::removePictures() { void FLAC::File::removePictures() {
for (BlockIterator it = d->blocks.begin(); it != d->blocks.end();) { for (BlockIterator it = d->blocks.begin(); it != d->blocks.end();) {
if (dynamic_cast<Picture *>(*it)) { if (dynamic_cast<Picture *>(*it)) {
delete *it; delete *it;
@@ -350,19 +339,22 @@ void FLAC::File::removePictures() {
++it; ++it;
} }
} }
} }
void FLAC::File::strip(int tags) { void FLAC::File::strip(int tags) {
if (tags & ID3v1) if (tags & ID3v1)
d->tag.set(FlacID3v1Index, 0); d->tag.set(FlacID3v1Index, nullptr);
if (tags & ID3v2) if (tags & ID3v2)
d->tag.set(FlacID3v2Index, 0); d->tag.set(FlacID3v2Index, nullptr);
if (tags & XiphComment) { if (tags & XiphComment) {
xiphComment()->removeAllFields(); xiphComment()->removeAllFields();
xiphComment()->removeAllPictures(); xiphComment()->removeAllPictures();
} }
} }
bool FLAC::File::hasXiphComment() const { bool FLAC::File::hasXiphComment() const {
@@ -382,6 +374,7 @@ bool FLAC::File::hasID3v2Tag() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void FLAC::File::read(bool readProperties) { void FLAC::File::read(bool readProperties) {
// Look for an ID3v2 tag // Look for an ID3v2 tag
d->ID3v2Location = Utils::findID3v2(this); d->ID3v2Location = Utils::findID3v2(this);
@@ -425,9 +418,11 @@ void FLAC::File::read(bool readProperties) {
d->properties = new Properties(infoData, streamLength); d->properties = new Properties(infoData, streamLength);
} }
} }
void FLAC::File::scan() { void FLAC::File::scan() {
// Scan the metadata pages // Scan the metadata pages
if (d->scanned) if (d->scanned)
@@ -494,7 +489,7 @@ void FLAC::File::scan() {
return; return;
} }
MetadataBlock *block = 0; MetadataBlock *block = nullptr;
// Found the vorbis-comment // Found the vorbis-comment
if (blockType == MetadataBlock::VorbisComment) { if (blockType == MetadataBlock::VorbisComment) {
@@ -537,4 +532,5 @@ void FLAC::File::scan() {
d->streamStart = nextBlockOffset; d->streamStart = nextBlockOffset;
d->scanned = true; d->scanned = true;
} }

View File

@@ -52,31 +52,30 @@ class XiphComment;
//! An implementation of FLAC metadata //! An implementation of FLAC metadata
/*! /*!
* This is implementation of FLAC metadata for non-Ogg FLAC files. At some * This is implementation of FLAC metadata for non-Ogg FLAC files. At some
* point when Ogg / FLAC is more common there will be a similar implementation * point when Ogg / FLAC is more common there will be a similar implementation
* under the Ogg hierarchy. * under the Ogg hierarchy.
* *
* This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream * This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
* properties from the file. * properties from the file.
*/ */
namespace FLAC { namespace FLAC {
//! An implementation of TagLib::File with FLAC specific methods //! An implementation of TagLib::File with FLAC specific methods
/*! /*!
* This implements and provides an interface for FLAC files to the * This implements and provides an interface for FLAC files to the TagLib::Tag and TagLib::AudioProperties interfaces
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * by way of implementing the abstract TagLib::File API as well as providing some additional information specific to FLAC files.
* the abstract TagLib::File API as well as providing some additional *
* information specific to FLAC files. */
*/
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* This set of flags is used for various operations and is suitable for * This set of flags is used for various operations and is suitable for
* being OR-ed together. * being OR-ed together.
*/ */
enum TagTypes { enum TagTypes {
//! Empty set. Matches no tag types. //! Empty set. Matches no tag types.
NoTags = 0x0000, NoTags = 0x0000,
@@ -91,247 +90,182 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
}; };
/*! /*!
* Constructs a FLAC file from \a file. If \a readProperties is true the * Constructs an FLAC file from \a file.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * If this file contains and ID3v2 tag the frames will be created using \a frameFactory.
* *
* \deprecated This constructor will be dropped in favor of the one below * \note In the current implementation, \a propertiesStyle is ignored.
* in a future version. */
*/ File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs an FLAC file from \a file. If \a readProperties is true the * Constructs a FLAC file from \a stream. If \a readProperties is true the file's audio properties will also be read.
* file's audio properties will also be read. *
* * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
* If this file contains and ID3v2 tag the frames will be created using *
* \a frameFactory. * If this file contains and ID3v2 tag the frames will be created using \a frameFactory.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * \note In the current implementation, \a propertiesStyle is ignored.
*/ */
// BIC: merge with the above constructor // BIC: merge with the above constructor
File(FileName file, ID3v2::FrameFactory *frameFactory, File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs a FLAC file from \a stream. If \a readProperties is true the * Destroys this instance of the File.
* file's audio properties will also be read. */
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* If this file contains and ID3v2 tag the frames will be created using
* \a frameFactory.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
// BIC: merge with the above constructor
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File(); virtual ~File();
/*! /*!
* Returns the Tag for this file. This will be a union of XiphComment, * Returns the Tag for this file. This will be a union of XiphComment, ID3v1 and ID3v2 tags.
* ID3v1 and ID3v2 tags. *
* * \see ID3v2Tag()
* \see ID3v2Tag() * \see ID3v1Tag()
* \see ID3v1Tag() * \see XiphComment()
* \see XiphComment() */
*/
virtual Strawberry_TagLib::TagLib::Tag *tag() const; virtual Strawberry_TagLib::TagLib::Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* If the file contains more than one tag (e.g. XiphComment and ID3v1), * If the file contains more than one tag (e.g. XiphComment and ID3v1), only the first one (in the order XiphComment, ID3v2, ID3v1) will be converted to the PropertyMap.
* only the first one (in the order XiphComment, ID3v2, ID3v1) will be */
* converted to the PropertyMap.
*/
PropertyMap properties() const; PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &); void removeUnsupportedProperties(const StringList &);
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* This always creates a Xiph comment, if none exists. The return value * This always creates a Xiph comment, if none exists. The return value relates to the Xiph comment only.
* relates to the Xiph comment only. * Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed in the FLAC specification.
* Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed */
* in the FLAC specification.
*/
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the FLAC::Properties for this file. If no audio properties * Returns the FLAC::Properties for this file. If no audio properties were read then this will return a null pointer.
* were read then this will return a null pointer. */
*/
virtual Properties *audioProperties() const; virtual Properties *audioProperties() const;
/*! /*!
* Save the file. This will primarily save the XiphComment, but * Save the file. This will primarily save the XiphComment, but will also keep any old ID3-tags up to date.
* will also keep any old ID3-tags up to date. If the file * If the file has no XiphComment, one will be constructed from the ID3-tags.
* has no XiphComment, one will be constructed from the ID3-tags. *
* * This returns true if the save was successful.
* This returns true if the save was successful. */
*/
virtual bool save(); virtual bool save();
/*! /*!
* Returns a pointer to the ID3v2 tag of the file. * Returns a pointer to the ID3v2 tag of the file.
* *
* If \a create is false (the default) this returns a null pointer * If \a create is false (the default) this returns a null pointer
* if there is no valid ID3v2 tag. If \a create is true it will create * if there is no valid ID3v2 tag.
* an ID3v2 tag if one does not exist and returns a valid pointer. * If \a create is true it will create an ID3v2 tag if one does not exist and returns a valid pointer.
* *
* \note This may return a valid pointer regardless of whether or not the * \note This may return a valid pointer regardless of whether or not the file on disk has an ID3v2 tag.
* file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file * Use hasID3v2Tag() to check if the file on disk actually has an ID3v2 tag.
* on disk actually has an ID3v2 tag. *
* * \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is destroyed.
* deleted by the user. It will be deleted when the file (object) is *
* destroyed. * \see hasID3v2Tag()
* */
* \see hasID3v2Tag()
*/
ID3v2::Tag *ID3v2Tag(bool create = false); ID3v2::Tag *ID3v2Tag(bool create = false);
/*! /*!
* Returns a pointer to the ID3v1 tag of the file. * Returns a pointer to the ID3v1 tag of the file.
* *
* If \a create is false (the default) this returns a null pointer * If \a create is false (the default) this returns a null pointer if there is no valid APE tag.
* if there is no valid APE tag. If \a create is true it will create * If \a create is true it will create an APE tag if one does not exist and returns a valid pointer.
* an APE tag if one does not exist and returns a valid pointer. *
* * \note This may return a valid pointer regardless of whether or not the file on disk has an ID3v1 tag.
* \note This may return a valid pointer regardless of whether or not the * Use hasID3v1Tag() to check if the file on disk actually has an ID3v1 tag.
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file *
* on disk actually has an ID3v1 tag. * \note The Tag <b>is still</b> owned by the MPEG::File and should not be deleted by the user.
* * It will be deleted when the file (object) is destroyed.
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be *
* deleted by the user. It will be deleted when the file (object) is * \see hasID3v1Tag()
* destroyed. */
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false); ID3v1::Tag *ID3v1Tag(bool create = false);
/*! /*!
* Returns a pointer to the XiphComment for the file. * Returns a pointer to the XiphComment for the file.
* *
* If \a create is false (the default) this returns a null pointer * If \a create is false (the default) this returns a null pointer if there is no valid XiphComment.
* if there is no valid XiphComment. If \a create is true it will create * If \a create is true it will create a XiphComment if one does not exist and returns a valid pointer.
* a XiphComment if one does not exist and returns a valid pointer. *
* * \note This may return a valid pointer regardless of whether or not the file on disk has a XiphComment.
* \note This may return a valid pointer regardless of whether or not the * Use hasXiphComment() to check if the file on disk actually has a XiphComment.
* file on disk has a XiphComment. Use hasXiphComment() to check if the *
* file on disk actually has a XiphComment. * \note The Tag <b>is still</b> owned by the FLAC::File and should not be deleted by the user.
* * It will be deleted when the file (object) is destroyed.
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be *
* deleted by the user. It will be deleted when the file (object) is * \see hasXiphComment()
* destroyed. */
*
* \see hasXiphComment()
*/
Ogg::XiphComment *xiphComment(bool create = false); Ogg::XiphComment *xiphComment(bool create = false);
/*! /*!
* Set the ID3v2::FrameFactory to something other than the default. This * Returns a list of pictures attached to the FLAC file.
* can be used to specify the way that ID3v2 frames will be interpreted */
* when
*
* \see ID3v2FrameFactory
* \deprecated This value should be passed in via the constructor
*/
TAGLIB_DEPRECATED void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
/*!
* Returns the block of data used by FLAC::Properties for parsing the
* stream properties.
*
* \deprecated Always returns an empty vector.
*/
TAGLIB_DEPRECATED ByteVector streamInfoData(); // BIC: remove
/*!
* Returns the length of the audio-stream, used by FLAC::Properties for
* calculating the bitrate.
*
* \deprecated Always returns zero.
*/
TAGLIB_DEPRECATED long streamLength(); // BIC: remove
/*!
* Returns a list of pictures attached to the FLAC file.
*/
List<Picture *> pictureList(); List<Picture *> pictureList();
/*! /*!
* Removes an attached picture. If \a del is true the picture's memory * Removes an attached picture.
* will be freed; if it is false, it must be deleted by the user. * If \a del is true the picture's memory will be freed; if it is false, it must be deleted by the user.
*/ */
void removePicture(Picture *picture, bool del = true); void removePicture(Picture *picture, bool del = true);
/*! /*!
* Remove all attached images. * Remove all attached images.
*/ */
void removePictures(); void removePictures();
/*! /*!
* Add a new picture to the file. The file takes ownership of the * Add a new picture to the file.
* picture and will handle freeing its memory. * The file takes ownership of the picture and will handle freeing its memory.
* *
* \note The file will be saved only after calling save(). * \note The file will be saved only after calling save().
*/ */
void addPicture(Picture *picture); void addPicture(Picture *picture);
/*! /*!
* This will remove the tags that match the OR-ed together TagTypes from * This will remove the tags that match the OR-ed together TagTypes from the file.
* the file. By default it removes all tags. * By default it removes all tags.
* *
* \warning This will also invalidate pointers to the tags as their memory * \warning This will also invalidate pointers to the tags as their memory will be freed.
* will be freed. *
* * \note In order to make the removal permanent save() still needs to be called.
* \note In order to make the removal permanent save() still needs to be *
* called. * \note This won't remove the Vorbis comment block completely.
* * The vendor ID will be preserved.
* \note This won't remove the Vorbis comment block completely. The */
* vendor ID will be preserved.
*/
void strip(int tags = AllTags); void strip(int tags = AllTags);
/*! /*!
* Returns whether or not the file on disk actually has a XiphComment. * Returns whether or not the file on disk actually has a XiphComment.
* *
* \see xiphComment() * \see xiphComment()
*/ */
bool hasXiphComment() const; bool hasXiphComment() const;
/*! /*!
* Returns whether or not the file on disk actually has an ID3v1 tag. * Returns whether or not the file on disk actually has an ID3v1 tag.
* *
* \see ID3v1Tag() * \see ID3v1Tag()
*/ */
bool hasID3v1Tag() const; bool hasID3v1Tag() const;
/*! /*!
* Returns whether or not the file on disk actually has an ID3v2 tag. * Returns whether or not the file on disk actually has an ID3v2 tag.
* *
* \see ID3v2Tag() * \see ID3v2Tag()
*/ */
bool hasID3v2Tag() const; bool hasID3v2Tag() const;
/*! /*!
* Returns whether or not the given \a stream can be opened as a FLAC * Returns whether or not the given \a stream can be opened as a FLAC file.
* file. *
* * \note This method is designed to do a quick check.
* \note This method is designed to do a quick check. The result may * The result may not necessarily be correct.
* not necessarily be correct. */
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
private: private:

View File

@@ -34,9 +34,6 @@ class FLAC::MetadataBlock::MetadataBlockPrivate {
MetadataBlockPrivate() {} MetadataBlockPrivate() {}
}; };
FLAC::MetadataBlock::MetadataBlock() { FLAC::MetadataBlock::MetadataBlock() : d(nullptr) {}
d = 0;
}
FLAC::MetadataBlock::~MetadataBlock() { FLAC::MetadataBlock::~MetadataBlock() {}
}

View File

@@ -32,7 +32,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace FLAC { namespace FLAC {
class TAGLIB_EXPORT MetadataBlock { class TAGLIB_EXPORT MetadataBlock {
@@ -69,7 +68,6 @@ class TAGLIB_EXPORT MetadataBlock {
}; };
} // namespace FLAC } // namespace FLAC
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -64,6 +64,7 @@ int FLAC::Picture::code() const {
} }
bool FLAC::Picture::parse(const ByteVector &data) { bool FLAC::Picture::parse(const ByteVector &data) {
if (data.size() < 32) { if (data.size() < 32) {
debug("A picture block must contain at least 5 bytes."); debug("A picture block must contain at least 5 bytes.");
return false; return false;
@@ -105,9 +106,11 @@ bool FLAC::Picture::parse(const ByteVector &data) {
d->data = data.mid(pos, dataLength); d->data = data.mid(pos, dataLength);
return true; return true;
} }
ByteVector FLAC::Picture::render() const { ByteVector FLAC::Picture::render() const {
ByteVector result; ByteVector result;
result.append(ByteVector::fromUInt(d->type)); result.append(ByteVector::fromUInt(d->type));
ByteVector mimeTypeData = d->mimeType.data(String::UTF8); ByteVector mimeTypeData = d->mimeType.data(String::UTF8);
@@ -123,6 +126,7 @@ ByteVector FLAC::Picture::render() const {
result.append(ByteVector::fromUInt(d->data.size())); result.append(ByteVector::fromUInt(d->data.size()));
result.append(d->data); result.append(d->data);
return result; return result;
} }
FLAC::Picture::Type FLAC::Picture::type() const { FLAC::Picture::Type FLAC::Picture::type() const {

View File

@@ -40,8 +40,8 @@ namespace FLAC {
class TAGLIB_EXPORT Picture : public MetadataBlock { class TAGLIB_EXPORT Picture : public MetadataBlock {
public: public:
/*! /*!
* This describes the function or content of the picture. * This describes the function or content of the picture.
*/ */
enum Type { enum Type {
//! A type not enumerated below //! A type not enumerated below
Other = 0x00, Other = 0x00,
@@ -92,102 +92,100 @@ class TAGLIB_EXPORT Picture : public MetadataBlock {
~Picture(); ~Picture();
/*! /*!
* Returns the type of the image. * Returns the type of the image.
*/ */
Type type() const; Type type() const;
/*! /*!
* Sets the type of the image. * Sets the type of the image.
*/ */
void setType(Type type); void setType(Type type);
/*! /*!
* Returns the mime type of the image. This should in most cases be * Returns the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
* "image/png" or "image/jpeg". */
*/
String mimeType() const; String mimeType() const;
/*! /*!
* Sets the mime type of the image. This should in most cases be * Sets the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
* "image/png" or "image/jpeg". */
*/
void setMimeType(const String &m); void setMimeType(const String &m);
/*! /*!
* Returns a text description of the image. * Returns a text description of the image.
*/ */
String description() const; String description() const;
/*! /*!
* Sets a textual description of the image to \a desc. * Sets a textual description of the image to \a desc.
*/ */
void setDescription(const String &desc); void setDescription(const String &desc);
/*! /*!
* Returns the width of the image. * Returns the width of the image.
*/ */
int width() const; int width() const;
/*! /*!
* Sets the width of the image. * Sets the width of the image.
*/ */
void setWidth(int w); void setWidth(int w);
/*! /*!
* Returns the height of the image. * Returns the height of the image.
*/ */
int height() const; int height() const;
/*! /*!
* Sets the height of the image. * Sets the height of the image.
*/ */
void setHeight(int h); void setHeight(int h);
/*! /*!
* Returns the color depth (in bits-per-pixel) of the image. * Returns the color depth (in bits-per-pixel) of the image.
*/ */
int colorDepth() const; int colorDepth() const;
/*! /*!
* Sets the color depth (in bits-per-pixel) of the image. * Sets the color depth (in bits-per-pixel) of the image.
*/ */
void setColorDepth(int depth); void setColorDepth(int depth);
/*! /*!
* Returns the number of colors used on the image.. * Returns the number of colors used on the image..
*/ */
int numColors() const; int numColors() const;
/*! /*!
* Sets the number of colors used on the image (for indexed images). * Sets the number of colors used on the image (for indexed images).
*/ */
void setNumColors(int numColors); void setNumColors(int numColors);
/*! /*!
* Returns the image data. * Returns the image data.
*/ */
ByteVector data() const; ByteVector data() const;
/*! /*!
* Sets the image data. * Sets the image data.
*/ */
void setData(const ByteVector &data); void setData(const ByteVector &data);
/*! /*!
* Returns the FLAC metadata block type. * Returns the FLAC metadata block type.
*/ */
int code() const; int code() const;
/*! /*!
* Render the content to the FLAC picture block format. * Render the content to the FLAC picture block format.
*/ */
ByteVector render() const; ByteVector render() const;
/*! /*!
* Parse the picture data in the FLAC picture block format. * Parse the picture data in the FLAC picture block format.
*/ */
bool parse(const ByteVector &rawData); bool parse(const ByteVector &rawData);
private: private:
@@ -201,7 +199,6 @@ class TAGLIB_EXPORT Picture : public MetadataBlock {
typedef List<Picture> PictureList; typedef List<Picture> PictureList;
} // namespace FLAC } // namespace FLAC
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -53,24 +53,14 @@ class FLAC::Properties::PropertiesPrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style), FLAC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
d(new PropertiesPrivate()) {
read(data, streamLength); read(data, streamLength);
} }
FLAC::Properties::Properties(File *, ReadStyle style) : AudioProperties(style),
d(new PropertiesPrivate()) {
debug("FLAC::Properties::Properties() - This constructor is no longer used.");
}
FLAC::Properties::~Properties() { FLAC::Properties::~Properties() {
delete d; delete d;
} }
int FLAC::Properties::length() const {
return lengthInSeconds();
}
int FLAC::Properties::lengthInSeconds() const { int FLAC::Properties::lengthInSeconds() const {
return d->length / 1000; return d->length / 1000;
} }
@@ -91,10 +81,6 @@ int FLAC::Properties::bitsPerSample() const {
return d->bitsPerSample; return d->bitsPerSample;
} }
int FLAC::Properties::sampleWidth() const {
return bitsPerSample();
}
int FLAC::Properties::channels() const { int FLAC::Properties::channels() const {
return d->channels; return d->channels;
} }
@@ -112,6 +98,7 @@ ByteVector FLAC::Properties::signature() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void FLAC::Properties::read(const ByteVector &data, long streamLength) { void FLAC::Properties::read(const ByteVector &data, long streamLength) {
if (data.size() < 18) { if (data.size() < 18) {
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes."); debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
return; return;
@@ -155,4 +142,5 @@ void FLAC::Properties::read(const ByteVector &data, long streamLength) {
if (data.size() >= pos + 16) if (data.size() >= pos + 16)
d->signature = data.mid(pos, 16); d->signature = data.mid(pos, 16);
} }

View File

@@ -39,98 +39,65 @@ class File;
//! An implementation of audio property reading for FLAC //! An implementation of audio property reading for FLAC
/*! /*!
* This reads the data from an FLAC stream found in the AudioProperties * This reads the data from an FLAC stream found in the AudioProperties API.
* API. */
*/
class TAGLIB_EXPORT Properties : public AudioProperties { class TAGLIB_EXPORT Properties : public AudioProperties {
public: public:
/*! /*!
* Create an instance of FLAC::Properties with the data read from the * Create an instance of FLAC::Properties with the data read from the ByteVector \a data.
* ByteVector \a data. */
*/ Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
// BIC: switch to const reference
Properties(ByteVector data, long streamLength, ReadStyle style = Average);
/*! /*!
* Create an instance of FLAC::Properties with the data read from the * Destroys this FLAC::Properties instance.
* FLAC::File \a file. */
*/
// BIC: remove
Properties(File *file, ReadStyle style = Average);
/*!
* Destroys this FLAC::Properties instance.
*/
virtual ~Properties(); virtual ~Properties();
/*! /*!
* Returns the length of the file in seconds. The length is rounded down to * Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
* the nearest whole second. *
* * \see lengthInMilliseconds()
* \note This method is just an alias of lengthInSeconds(). */
*
* \deprecated
*/
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual // BIC: make virtual
int lengthInSeconds() const; int lengthInSeconds() const;
/*! /*!
* Returns the length of the file in milliseconds. * Returns the length of the file in milliseconds.
* *
* \see lengthInSeconds() * \see lengthInSeconds()
*/ */
// BIC: make virtual // BIC: make virtual
int lengthInMilliseconds() const; int lengthInMilliseconds() const;
/*! /*!
* Returns the average bit rate of the file in kb/s. * Returns the average bit rate of the file in kb/s.
*/ */
virtual int bitrate() const; virtual int bitrate() const;
/*! /*!
* Returns the sample rate in Hz. * Returns the sample rate in Hz.
*/ */
virtual int sampleRate() const; virtual int sampleRate() const;
/*! /*!
* Returns the number of audio channels. * Returns the number of audio channels.
*/ */
virtual int channels() const; virtual int channels() const;
/*! /*!
* Returns the number of bits per audio sample as read from the FLAC * Returns the number of bits per audio sample as read from the FLAC identification header.
* identification header. */
*/
int bitsPerSample() const; int bitsPerSample() const;
/*! /*!
* Returns the sample width as read from the FLAC identification * Return the number of sample frames.
* header. */
*
* \note This method is just an alias of bitsPerSample().
*
* \deprecated
*/
TAGLIB_DEPRECATED int sampleWidth() const;
/*!
* Return the number of sample frames.
*/
unsigned long long sampleFrames() const; unsigned long long sampleFrames() const;
/*! /*!
* Returns the MD5 signature of the uncompressed audio stream as read * Returns the MD5 signature of the uncompressed audio stream as read from the stream info header.
* from the stream info header. */
*/
ByteVector signature() const; ByteVector signature() const;
private: private:

View File

@@ -33,7 +33,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace FLAC { namespace FLAC {
class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock { class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
@@ -42,28 +41,28 @@ class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
~UnknownMetadataBlock(); ~UnknownMetadataBlock();
/*! /*!
* Returns the FLAC metadata block type. * Returns the FLAC metadata block type.
*/ */
int code() const; int code() const;
/*! /*!
* Sets the FLAC metadata block type. * Sets the FLAC metadata block type.
*/ */
void setCode(int code); void setCode(int code);
/*! /*!
* Returns the FLAC metadata block type. * Returns the FLAC metadata block type.
*/ */
ByteVector data() const; ByteVector data() const;
/*! /*!
* Sets the FLAC metadata block type. * Sets the FLAC metadata block type.
*/ */
void setData(const ByteVector &data); void setData(const ByteVector &data);
/*! /*!
* Render the content of the block. * Render the content of the block.
*/ */
ByteVector render() const; ByteVector render() const;
private: private:
@@ -75,7 +74,6 @@ class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
}; };
} // namespace FLAC } // namespace FLAC
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -35,26 +35,26 @@ using namespace IT;
class IT::File::FilePrivate { class IT::File::FilePrivate {
public: public:
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle) explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle) : tag(), properties(propertiesStyle) {}
: tag(), properties(propertiesStyle) {
}
Mod::Tag tag; Mod::Tag tag;
IT::Properties properties; IT::Properties properties;
}; };
IT::File::File(FileName file, bool readProperties, IT::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) {
d(new FilePrivate(propertiesStyle)) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
IT::File::File(IOStream *stream, bool readProperties, IT::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) {
d(new FilePrivate(propertiesStyle)) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
IT::File::~File() { IT::File::~File() {
@@ -78,6 +78,7 @@ IT::Properties *IT::File::audioProperties() const {
} }
bool IT::File::save() { bool IT::File::save() {
if (readOnly()) { if (readOnly()) {
debug("IT::File::save() - Cannot save to a read only file."); debug("IT::File::save() - Cannot save to a read only file.");
return false; return false;
@@ -317,4 +318,5 @@ void IT::File::read(bool) {
comment.append(message); comment.append(message);
d->tag.setComment(comment.toString("\n")); d->tag.setComment(comment.toString("\n"));
d->tag.setTrackerName("Impulse Tracker"); d->tag.setTrackerName("Impulse Tracker");
} }

View File

@@ -31,67 +31,63 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace IT { namespace IT {
class TAGLIB_EXPORT File : public Mod::FileBase { class TAGLIB_EXPORT File : public Mod::FileBase {
public: public:
/*! /*!
* Constructs a Impulse Tracker file from \a file. * Constructs a Impulse Tracker file from \a file.
* *
* \note In the current implementation, both \a readProperties and * \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
* \a propertiesStyle are ignored. The audio properties are always * The audio properties are always read.
* read. */
*/
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average); AudioProperties::Average);
/*! /*!
* Constructs a Impulse Tracker file from \a stream. * Constructs a Impulse Tracker file from \a stream.
* *
* \note In the current implementation, both \a readProperties and * \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
* \a propertiesStyle are ignored. The audio properties are always * The audio properties are always read.
* read. *
* * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
* \note TagLib will *not* take ownership of the stream, the caller is */
* responsible for deleting it after the File object.
*/
File(IOStream *stream, bool readProperties = true, File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average); AudioProperties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
Mod::Tag *tag() const; Mod::Tag *tag() const;
/*! /*!
* Forwards to Mod::Tag::properties(). * Forwards to Mod::Tag::properties().
* BIC: will be removed once File::toDict() is made virtual * BIC: will be removed once File::toDict() is made virtual
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Forwards to Mod::Tag::setProperties(). * Forwards to Mod::Tag::setProperties().
* BIC: will be removed once File::setProperties() is made virtual * BIC: will be removed once File::setProperties() is made virtual
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the IT::Properties for this file. If no audio properties * Returns the IT::Properties for this file. If no audio properties
* were read then this will return a null pointer. * were read then this will return a null pointer.
*/ */
IT::Properties *audioProperties() const; IT::Properties *audioProperties() const;
/*! /*!
* Save the file. * Save the file.
* This is the same as calling save(AllTags); * This is the same as calling save(AllTags);
* *
* \note Saving Impulse Tracker tags is not supported. * \note Saving Impulse Tracker tags is not supported.
*/ */
bool save(); bool save();
@@ -104,6 +100,7 @@ class TAGLIB_EXPORT File : public Mod::FileBase {
class FilePrivate; class FilePrivate;
FilePrivate *d; FilePrivate *d;
}; };
} // namespace IT } // namespace IT
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -65,9 +65,7 @@ class IT::Properties::PropertiesPrivate {
unsigned char pitchWheelDepth; unsigned char pitchWheelDepth;
}; };
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate()) {}
d(new PropertiesPrivate()) {
}
IT::Properties::~Properties() { IT::Properties::~Properties() {
delete d; delete d;

View File

@@ -35,26 +35,24 @@ using namespace Mod;
class Mod::File::FilePrivate { class Mod::File::FilePrivate {
public: public:
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle) explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle) : properties(propertiesStyle) {}
: properties(propertiesStyle) {
}
Mod::Tag tag; Mod::Tag tag;
Mod::Properties properties; Mod::Properties properties;
}; };
Mod::File::File(FileName file, bool readProperties, Mod::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) {
AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file),
d(new FilePrivate(propertiesStyle)) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
Mod::File::File(IOStream *stream, bool readProperties, Mod::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) {
AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream),
d(new FilePrivate(propertiesStyle)) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
Mod::File::~File() { Mod::File::~File() {
@@ -78,6 +76,7 @@ PropertyMap Mod::File::setProperties(const PropertyMap &properties) {
} }
bool Mod::File::save() { bool Mod::File::save() {
if (readOnly()) { if (readOnly()) {
debug("Mod::File::save() - Cannot save to a read only file."); debug("Mod::File::save() - Cannot save to a read only file.");
return false; return false;
@@ -96,9 +95,11 @@ bool Mod::File::save() {
seek(8, Current); seek(8, Current);
} }
return true; return true;
} }
void Mod::File::read(bool) { void Mod::File::read(bool) {
if (!isOpen()) if (!isOpen())
return; return;
@@ -176,4 +177,5 @@ void Mod::File::read(bool) {
READ_BYTE(d->properties.setLengthInPatterns); READ_BYTE(d->properties.setLengthInPatterns);
d->tag.setComment(comment.toString("\n")); d->tag.setComment(comment.toString("\n"));
} }

View File

@@ -35,66 +35,58 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace Mod { namespace Mod {
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
public: public:
/*! /*!
* Constructs a Protracker file from \a file. * Constructs a Protracker file from \a file.
* *
* \note In the current implementation, both \a readProperties and * \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
* \a propertiesStyle are ignored. The audio properties are always * The audio properties are always read.
* read. */
*/ File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
File(FileName file, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*! /*!
* Constructs a Protracker file from \a stream. * Constructs a Protracker file from \a stream.
* *
* \note In the current implementation, both \a readProperties and * \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
* \a propertiesStyle are ignored. The audio properties are always * The audio properties are always read.
* read. *
* * \note TagLib will *not* take ownership of the stream, the caller is
* \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object.
* responsible for deleting it after the File object. */
*/ File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
Mod::Tag *tag() const; Mod::Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* Forwards to Mod::Tag::properties(). * Forwards to Mod::Tag::properties().
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* Forwards to Mod::Tag::setProperties(). * Forwards to Mod::Tag::setProperties().
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the Mod::Properties for this file. If no audio properties * Returns the Mod::Properties for this file. If no audio properties were read then this will return a null pointer.
* were read then this will return a null pointer. */
*/
Mod::Properties *audioProperties() const; Mod::Properties *audioProperties() const;
/*! /*!
* Save the file. * Save the file.
* This is the same as calling save(AllTags); * This is the same as calling save(AllTags);
* *
* \note Saving Protracker tags is not supported. * \note Saving Protracker tags is not supported.
*/ */
bool save(); bool save();
private: private:
@@ -108,7 +100,6 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
}; };
} // namespace Mod } // namespace Mod
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -30,11 +30,9 @@
using namespace Strawberry_TagLib::TagLib; using namespace Strawberry_TagLib::TagLib;
using namespace Mod; using namespace Mod;
Mod::FileBase::FileBase(FileName file) : Strawberry_TagLib::TagLib::File(file) { Mod::FileBase::FileBase(FileName file) : Strawberry_TagLib::TagLib::File(file) {}
}
Mod::FileBase::FileBase(IOStream *stream) : Strawberry_TagLib::TagLib::File(stream) { Mod::FileBase::FileBase(IOStream *stream) : Strawberry_TagLib::TagLib::File(stream) {}
}
void Mod::FileBase::writeString(const String &s, unsigned long size, char padding) { void Mod::FileBase::writeString(const String &s, unsigned long size, char padding) {
ByteVector data(s.data(String::Latin1)); ByteVector data(s.data(String::Latin1));
@@ -43,6 +41,7 @@ void Mod::FileBase::writeString(const String &s, unsigned long size, char paddin
} }
bool Mod::FileBase::readString(String &s, unsigned long size) { bool Mod::FileBase::readString(String &s, unsigned long size) {
ByteVector data(readBlock(size)); ByteVector data(readBlock(size));
if (data.size() < size) return false; if (data.size() < size) return false;
int index = data.find((char)0); int index = data.find((char)0);
@@ -53,6 +52,7 @@ bool Mod::FileBase::readString(String &s, unsigned long size) {
s = data; s = data;
return true; return true;
} }
void Mod::FileBase::writeByte(unsigned char _byte) { void Mod::FileBase::writeByte(unsigned char _byte) {
@@ -77,36 +77,46 @@ void Mod::FileBase::writeU32B(unsigned long number) {
} }
bool Mod::FileBase::readByte(unsigned char &_byte) { bool Mod::FileBase::readByte(unsigned char &_byte) {
ByteVector data(readBlock(1)); ByteVector data(readBlock(1));
if (data.size() < 1) return false; if (data.size() < 1) return false;
_byte = data[0]; _byte = data[0];
return true; return true;
} }
bool Mod::FileBase::readU16L(unsigned short &number) { bool Mod::FileBase::readU16L(unsigned short &number) {
ByteVector data(readBlock(2)); ByteVector data(readBlock(2));
if (data.size() < 2) return false; if (data.size() < 2) return false;
number = data.toUShort(false); number = data.toUShort(false);
return true; return true;
} }
bool Mod::FileBase::readU32L(unsigned long &number) { bool Mod::FileBase::readU32L(unsigned long &number) {
ByteVector data(readBlock(4)); ByteVector data(readBlock(4));
if (data.size() < 4) return false; if (data.size() < 4) return false;
number = data.toUInt(false); number = data.toUInt(false);
return true; return true;
} }
bool Mod::FileBase::readU16B(unsigned short &number) { bool Mod::FileBase::readU16B(unsigned short &number) {
ByteVector data(readBlock(2)); ByteVector data(readBlock(2));
if (data.size() < 2) return false; if (data.size() < 2) return false;
number = data.toUShort(true); number = data.toUShort(true);
return true; return true;
} }
bool Mod::FileBase::readU32B(unsigned long &number) { bool Mod::FileBase::readU32B(unsigned long &number) {
ByteVector data(readBlock(4)); ByteVector data(readBlock(4));
if (data.size() < 4) return false; if (data.size() < 4) return false;
number = data.toUInt(true); number = data.toUInt(true);
return true; return true;
} }

View File

@@ -36,7 +36,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace Mod { namespace Mod {
class TAGLIB_EXPORT FileBase : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT FileBase : public Strawberry_TagLib::TagLib::File {
@@ -60,7 +59,6 @@ class TAGLIB_EXPORT FileBase : public Strawberry_TagLib::TagLib::File {
}; };
} // namespace Mod } // namespace Mod
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -31,18 +31,14 @@ using namespace Mod;
class Mod::Properties::PropertiesPrivate { class Mod::Properties::PropertiesPrivate {
public: public:
PropertiesPrivate() : channels(0), PropertiesPrivate() : channels(0), instrumentCount(0), lengthInPatterns(0) {}
instrumentCount(0),
lengthInPatterns(0) {
}
int channels; int channels;
unsigned int instrumentCount; unsigned int instrumentCount;
unsigned char lengthInPatterns; unsigned char lengthInPatterns;
}; };
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate()) {
d(new PropertiesPrivate()) {
} }
Mod::Properties::~Properties() { Mod::Properties::~Properties() {

View File

@@ -31,7 +31,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace Mod { namespace Mod {
class TAGLIB_EXPORT Properties : public AudioProperties { class TAGLIB_EXPORT Properties : public AudioProperties {
@@ -65,7 +64,6 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
}; };
} // namespace Mod } // namespace Mod
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -33,17 +33,14 @@ using namespace Mod;
class Mod::Tag::TagPrivate { class Mod::Tag::TagPrivate {
public: public:
TagPrivate() { TagPrivate() {}
}
String title; String title;
String comment; String comment;
String trackerName; String trackerName;
}; };
Mod::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), Mod::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), d(new TagPrivate()) {}
d(new TagPrivate()) {
}
Mod::Tag::~Tag() { Mod::Tag::~Tag() {
delete d; delete d;
@@ -109,15 +106,18 @@ void Mod::Tag::setTrackerName(const String &trackerName) {
} }
PropertyMap Mod::Tag::properties() const { PropertyMap Mod::Tag::properties() const {
PropertyMap properties; PropertyMap properties;
properties["TITLE"] = d->title; properties["TITLE"] = d->title;
properties["COMMENT"] = d->comment; properties["COMMENT"] = d->comment;
if (!(d->trackerName.isEmpty())) if (!(d->trackerName.isEmpty()))
properties["TRACKERNAME"] = d->trackerName; properties["TRACKERNAME"] = d->trackerName;
return properties; return properties;
} }
PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) { PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) {
PropertyMap properties(origProps); PropertyMap properties(origProps);
properties.removeEmpty(); properties.removeEmpty();
StringList oneValueSet; StringList oneValueSet;
@@ -151,4 +151,5 @@ PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) {
properties[*it].erase(properties[*it].begin()); properties[*it].erase(properties[*it].begin());
} }
return properties; return properties;
} }

View File

@@ -30,153 +30,141 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace Mod { namespace Mod {
/*! /*!
* Tags for module files (Mod, S3M, IT, XM). * Tags for module files (Mod, S3M, IT, XM).
* *
* Note that only the \a title is supported as such by most * Note that only the \a title is supported as such by most module file formats.
* module file formats. Except for XM files the \a trackerName * Except for XM files the \a trackerName is derived from the file format or the flavour of the file format.
* is derived from the file format or the flavour of the file * For XM files it is stored in the file.
* format. For XM files it is stored in the file. *
* * The \a comment tag is not strictly supported by module files,
* The \a comment tag is not strictly supported by module files, * but it is common practice to abuse instrument/sample/pattern names as multiline comments.
* but it is common practice to abuse instrument/sample/pattern * TagLib does so as well.
* names as multiline comments. TagLib does so as well. *
*/ */
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public: public:
Tag(); Tag();
virtual ~Tag(); virtual ~Tag();
/*! /*!
* Returns the track name; if no track name is present in the tag * Returns the track name; if no track name is present in the tag String::null will be returned.
* String::null will be returned. */
*/
virtual String title() const; virtual String title() const;
/*! /*!
* Not supported by module files. Therefore always returns String::null. * Not supported by module files. Therefore always returns String::null.
*/ */
virtual String artist() const; virtual String artist() const;
/*! /*!
* Not supported by module files. Therefore always returns String::null. * Not supported by module files. Therefore always returns String::null.
*/ */
virtual String album() const; virtual String album() const;
/*! /*!
* Returns the track comment derived from the instrument/sample/pattern * Returns the track comment derived from the instrument/sample/pattern
* names; if no comment is present in the tag String::null will be * names; if no comment is present in the tag String::null will be returned.
* returned. */
*/
virtual String comment() const; virtual String comment() const;
/*! /*!
* Not supported by module files. Therefore always returns String::null. * Not supported by module files. Therefore always returns String::null.
*/ */
virtual String genre() const; virtual String genre() const;
/*! /*!
* Not supported by module files. Therefore always returns 0. * Not supported by module files. Therefore always returns 0.
*/ */
virtual unsigned int year() const; virtual unsigned int year() const;
/*! /*!
* Not supported by module files. Therefore always returns 0. * Not supported by module files. Therefore always returns 0.
*/ */
virtual unsigned int track() const; virtual unsigned int track() const;
/*! /*!
* Returns the name of the tracker used to create/edit the module file. * Returns the name of the tracker used to create/edit the module file.
* Only XM files store this tag to the file as such, for other formats * Only XM files store this tag to the file as such, for other formats
* (Mod, S3M, IT) this is derived from the file type or the flavour of * (Mod, S3M, IT) this is derived from the file type or the flavour of the file type.
* the file type. Therefore only XM files might have an empty * Therefore only XM files might have an empty (String::null) tracker name.
* (String::null) tracker name. */
*/
String trackerName() const; String trackerName() const;
/*! /*!
* Sets the title to \a title. If \a title is String::null then this * Sets the title to \a title.
* value will be cleared. * If \a title is String::null then this value will be cleared.
* *
* The length limits per file type are (1 character = 1 byte): * The length limits per file type are (1 character = 1 byte):
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 * Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 characters.
* characters. */
*/
virtual void setTitle(const String &title); virtual void setTitle(const String &title);
/*! /*!
* Not supported by module files and therefore ignored. * Not supported by module files and therefore ignored.
*/ */
virtual void setArtist(const String &artist); virtual void setArtist(const String &artist);
/*! /*!
* Not supported by module files and therefore ignored. * Not supported by module files and therefore ignored.
*/ */
virtual void setAlbum(const String &album); virtual void setAlbum(const String &album);
/*! /*!
* Sets the comment to \a comment. If \a comment is String::null then * Sets the comment to \a comment.
* this value will be cleared. * If \a comment is String::null then this value will be cleared.
* *
* Note that module file formats don't actually support a comment tag. * Note that module file formats don't actually support a comment tag.
* Instead the names of instruments/patterns/samples are abused as * Instead the names of instruments/patterns/samples are abused as a multiline comment.
* a multiline comment. Because of this the number of lines in a * Because of this the number of lines in a module file is fixed to the number of instruments/patterns/samples.
* module file is fixed to the number of instruments/patterns/samples. *
* * Also note that the instrument/pattern/sample name length is limited an thus the line length in comments are limited.
* Also note that the instrument/pattern/sample name length is limited * Too big comments will be truncated.
* an thus the line length in comments are limited. Too big comments *
* will be truncated. * The line length limits per file type are (1 character = 1 byte):
* * Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22 characters.
* The line length limits per file type are (1 character = 1 byte): */
* Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22
* characters.
*/
virtual void setComment(const String &comment); virtual void setComment(const String &comment);
/*! /*!
* Not supported by module files and therefore ignored. * Not supported by module files and therefore ignored.
*/ */
virtual void setGenre(const String &genre); virtual void setGenre(const String &genre);
/*! /*!
* Not supported by module files and therefore ignored. * Not supported by module files and therefore ignored.
*/ */
virtual void setYear(unsigned int year); virtual void setYear(unsigned int year);
/*! /*!
* Not supported by module files and therefore ignored. * Not supported by module files and therefore ignored.
*/ */
virtual void setTrack(unsigned int track); virtual void setTrack(unsigned int track);
/*! /*!
* Sets the tracker name to \a trackerName. If \a trackerName is * Sets the tracker name to \a trackerName.
* String::null then this value will be cleared. * If \a trackerName is String::null then this value will be cleared.
* *
* Note that only XM files support this tag. Setting the * Note that only XM files support this tag.
* tracker name for other module file formats will be ignored. * Setting the tracker name for other module file formats will be ignored.
* *
* The length of this tag is limited to 20 characters (1 character * The length of this tag is limited to 20 characters (1 character = 1 byte).
* = 1 byte). */
*/
void setTrackerName(const String &trackerName); void setTrackerName(const String &trackerName);
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* Since the module tag is very limited, the exported map is as well. * Since the module tag is very limited, the exported map is as well.
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* Because of the limitations of the module file tag, any tags besides * Because of the limitations of the module file tag, any tags besides COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be returned.
* COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be * Additionally, if the map contains tags with multiple values, all but the first will be contained in the returned map of unsupported properties.
* returned. Additionally, if the map contains tags with multiple values, */
* all but the first will be contained in the returned map of unsupported
* properties.
*/
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
private: private:
@@ -188,7 +176,6 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
}; };
} // namespace Mod } // namespace Mod
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -31,13 +31,10 @@
using namespace Strawberry_TagLib::TagLib; using namespace Strawberry_TagLib::TagLib;
const char *MP4::Atom::containers[11] = { const char *MP4::Atom::containers[11] = { "moov", "udta", "mdia", "meta", "ilst", "stbl", "minf", "moof", "traf", "trak", "stsd" };
"moov", "udta", "mdia", "meta", "ilst",
"stbl", "minf", "moof", "traf", "trak",
"stsd"
};
MP4::Atom::Atom(File *file) { MP4::Atom::Atom(File *file) {
children.setAutoDelete(true); children.setAutoDelete(true);
offset = file->tell(); offset = file->tell();
@@ -100,14 +97,14 @@ MP4::Atom::Atom(File *file) {
} }
file->seek(offset + length); file->seek(offset + length);
} }
MP4::Atom::~Atom() { MP4::Atom::~Atom() {}
}
MP4::Atom * MP4::Atom *MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4) {
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4) {
if (name1 == 0) { if (!name1) {
return this; return this;
} }
for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) { for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
@@ -116,10 +113,11 @@ MP4::Atom::find(const char *name1, const char *name2, const char *name3, const c
} }
} }
return nullptr; return nullptr;
} }
MP4::AtomList MP4::AtomList MP4::Atom::findall(const char *_name, bool recursive) {
MP4::Atom::findall(const char *_name, bool recursive) {
MP4::AtomList result; MP4::AtomList result;
for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) { for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
if ((*it)->name == _name) { if ((*it)->name == _name) {
@@ -130,11 +128,13 @@ MP4::Atom::findall(const char *_name, bool recursive) {
} }
} }
return result; return result;
} }
bool MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3) { bool MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3) {
path.append(this); path.append(this);
if (name1 == 0) { if (!name1) {
return true; return true;
} }
for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) { for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
@@ -143,9 +143,11 @@ bool MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2,
} }
} }
return false; return false;
} }
MP4::Atoms::Atoms(File *file) { MP4::Atoms::Atoms(File *file) {
atoms.setAutoDelete(true); atoms.setAutoDelete(true);
file->seek(0, File::End); file->seek(0, File::End);
@@ -157,23 +159,24 @@ MP4::Atoms::Atoms(File *file) {
if (atom->length == 0) if (atom->length == 0)
break; break;
} }
} }
MP4::Atoms::~Atoms() { MP4::Atoms::~Atoms() {}
}
MP4::Atom *MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4) {
MP4::Atom *
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4) {
for (AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) { for (AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
if ((*it)->name == name1) { if ((*it)->name == name1) {
return (*it)->find(name2, name3, name4); return (*it)->find(name2, name3, name4);
} }
} }
return nullptr; return nullptr;
} }
MP4::AtomList MP4::AtomList MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) {
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) {
MP4::AtomList path; MP4::AtomList path;
for (AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) { for (AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
if ((*it)->name == name1) { if ((*it)->name == name1) {
@@ -184,4 +187,5 @@ MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const
} }
} }
return path; return path;
} }

View File

@@ -35,7 +35,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace MP4 { namespace MP4 {
class Atom; class Atom;
@@ -78,6 +77,7 @@ class Atom {
public: public:
Atom(File *file); Atom(File *file);
~Atom(); ~Atom();
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0); bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0);
AtomList findall(const char *name, bool recursive = false); AtomList findall(const char *name, bool recursive = false);
@@ -96,13 +96,13 @@ class Atoms {
public: public:
Atoms(File *file); Atoms(File *file);
~Atoms(); ~Atoms();
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
AtomList atoms; AtomList atoms;
}; };
} // namespace MP4 } // namespace MP4
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -32,8 +32,7 @@ using namespace Strawberry_TagLib::TagLib;
class MP4::CoverArt::CoverArtPrivate : public RefCounter { class MP4::CoverArt::CoverArtPrivate : public RefCounter {
public: public:
CoverArtPrivate() : RefCounter(), CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {}
format(MP4::CoverArt::JPEG) {}
Format format; Format format;
ByteVector data; ByteVector data;

View File

@@ -33,14 +33,13 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace MP4 { namespace MP4 {
class TAGLIB_EXPORT CoverArt { class TAGLIB_EXPORT CoverArt {
public: public:
/*! /*!
* This describes the image type. * This describes the image type.
*/ */
enum Format { enum Format {
JPEG = TypeJPEG, JPEG = TypeJPEG,
PNG = TypePNG, PNG = TypePNG,
@@ -55,13 +54,13 @@ class TAGLIB_EXPORT CoverArt {
CoverArt(const CoverArt &item); CoverArt(const CoverArt &item);
/*! /*!
* Copies the contents of \a item into this CoverArt. * Copies the contents of \a item into this CoverArt.
*/ */
CoverArt &operator=(const CoverArt &item); CoverArt &operator=(const CoverArt &item);
/*! /*!
* Exchanges the content of the CoverArt by the content of \a item. * Exchanges the content of the CoverArt by the content of \a item.
*/ */
void swap(CoverArt &item); void swap(CoverArt &item);
//! Format of the image //! Format of the image
@@ -78,7 +77,6 @@ class TAGLIB_EXPORT CoverArt {
typedef List<CoverArt> CoverArtList; typedef List<CoverArt> CoverArtList;
} // namespace MP4 } // namespace MP4
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -36,6 +36,7 @@ using namespace Strawberry_TagLib::TagLib;
namespace { namespace {
bool checkValid(const MP4::AtomList &list) { bool checkValid(const MP4::AtomList &list) {
for (MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) { for (MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
if ((*it)->length == 0) if ((*it)->length == 0)
@@ -46,14 +47,13 @@ bool checkValid(const MP4::AtomList &list) {
} }
return true; return true;
} }
} // namespace } // namespace
class MP4::File::FilePrivate { class MP4::File::FilePrivate {
public: public:
FilePrivate() : tag(0), FilePrivate() : tag(nullptr), atoms(nullptr), properties(nullptr) {}
atoms(0),
properties(0) {}
~FilePrivate() { ~FilePrivate() {
delete atoms; delete atoms;
@@ -71,26 +71,30 @@ class MP4::File::FilePrivate {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool MP4::File::isSupported(IOStream *stream) { bool MP4::File::isSupported(IOStream *stream) {
// An MP4 file has to have an "ftyp" box first. // An MP4 file has to have an "ftyp" box first.
const ByteVector id = Utils::readHeader(stream, 8, false); const ByteVector id = Utils::readHeader(stream, 8, false);
return id.containsAt("ftyp", 4); return id.containsAt("ftyp", 4);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
MP4::File::~File() { MP4::File::~File() {
@@ -120,6 +124,7 @@ MP4::File::audioProperties() const {
} }
void MP4::File::read(bool readProperties) { void MP4::File::read(bool readProperties) {
if (!isValid()) if (!isValid())
return; return;
@@ -139,9 +144,11 @@ void MP4::File::read(bool readProperties) {
if (readProperties) { if (readProperties) {
d->properties = new Properties(this, d->atoms); d->properties = new Properties(this, d->atoms);
} }
} }
bool MP4::File::save() { bool MP4::File::save() {
if (readOnly()) { if (readOnly()) {
debug("MP4::File::save() -- File is read only."); debug("MP4::File::save() -- File is read only.");
return false; return false;
@@ -153,8 +160,9 @@ bool MP4::File::save() {
} }
return d->tag->save(); return d->tag->save();
} }
bool MP4::File::hasMP4Tag() const { bool MP4::File::hasMP4Tag() const {
return (d->atoms->find("moov", "udta", "meta", "ilst") != 0); return (d->atoms->find("moov", "udta", "meta", "ilst") != nullptr);
} }

View File

@@ -41,92 +41,85 @@ namespace MP4 {
class Atoms; class Atoms;
/*! /*!
* This implements and provides an interface for MP4 files to the * This implements and provides an interface for MP4 files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional * the abstract TagLib::File API as well as providing some additional
* information specific to MP4 files. * information specific to MP4 files.
*/ */
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* Constructs an MP4 file from \a file. If \a readProperties is true the * Constructs an MP4 file from \a file.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * \note In the current implementation, \a propertiesStyle is ignored.
*/ */
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
/*! /*!
* Constructs an MP4 file from \a stream. If \a readProperties is true the * Constructs an MP4 file from \a stream.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note TagLib will *not* take ownership of the stream, the caller is * \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object. * responsible for deleting it after the File object.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * \note In the current implementation, \a propertiesStyle is ignored.
*/ */
File(IOStream *stream, bool readProperties = true, File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle audioPropertiesStyle = Properties::Average); Properties::ReadStyle audioPropertiesStyle = Properties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
/*! /*!
* Returns a pointer to the MP4 tag of the file. * Returns a pointer to the MP4 tag of the file.
* *
* MP4::Tag implements the tag interface, so this serves as the * MP4::Tag implements the tag interface, so this serves as the reimplementation of TagLib::File::tag().
* reimplementation of TagLib::File::tag(). *
* * \note The Tag <b>is still</b> owned by the MP4::File and should not be deleted by the user.
* \note The Tag <b>is still</b> owned by the MP4::File and should not be * It will be deleted when the file (object) is destroyed.
* deleted by the user. It will be deleted when the file (object) is */
* destroyed.
*/
Tag *tag() const; Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
*/ */
PropertyMap properties() const; PropertyMap properties() const;
/*! /*!
* Removes unsupported properties. Forwards to the actual Tag's * Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
* removeUnsupportedProperties() function. */
*/
void removeUnsupportedProperties(const StringList &properties); void removeUnsupportedProperties(const StringList &properties);
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the MP4 audio properties for this file. * Returns the MP4 audio properties for this file.
*/ */
Properties *audioProperties() const; Properties *audioProperties() const;
/*! /*!
* Save the file. * Save the file.
* *
* This returns true if the save was successful. * This returns true if the save was successful.
*/ */
bool save(); bool save();
/*! /*!
* Returns whether or not the file on disk actually has an MP4 tag, or the * Returns whether or not the file on disk actually has an MP4 tag, or the file has a Metadata Item List (ilst) atom.
* file has a Metadata Item List (ilst) atom. */
*/
bool hasMP4Tag() const; bool hasMP4Tag() const;
/*! /*!
* Returns whether or not the given \a stream can be opened as an ASF * Returns whether or not the given \a stream can be opened as an ASF file.
* file. *
* * \note This method is designed to do a quick check. The result may not necessarily be correct.
* \note This method is designed to do a quick check. The result may */
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
private: private:
@@ -137,7 +130,6 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
}; };
} // namespace MP4 } // namespace MP4
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -32,9 +32,7 @@ using namespace Strawberry_TagLib::TagLib;
class MP4::Item::ItemPrivate : public RefCounter { class MP4::Item::ItemPrivate : public RefCounter {
public: public:
ItemPrivate() : RefCounter(), ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {}
valid(true),
atomDataType(TypeUndefined) {}
bool valid; bool valid;
AtomDataType atomDataType; AtomDataType atomDataType;
@@ -59,8 +57,7 @@ MP4::Item::Item(const Item &item) : d(item.d) {
d->ref(); d->ref();
} }
MP4::Item & MP4::Item &MP4::Item::operator=(const Item &item) {
MP4::Item::operator=(const Item &item) {
Item(item).swap(*this); Item(item).swap(*this);
return *this; return *this;
} }
@@ -129,38 +126,31 @@ int MP4::Item::toInt() const {
return d->m_int; return d->m_int;
} }
unsigned char unsigned char MP4::Item::toByte() const {
MP4::Item::toByte() const {
return d->m_byte; return d->m_byte;
} }
unsigned int unsigned int MP4::Item::toUInt() const {
MP4::Item::toUInt() const {
return d->m_uint; return d->m_uint;
} }
long long long long MP4::Item::toLongLong() const {
MP4::Item::toLongLong() const {
return d->m_longlong; return d->m_longlong;
} }
MP4::Item::IntPair MP4::Item::IntPair MP4::Item::toIntPair() const {
MP4::Item::toIntPair() const {
return d->m_intPair; return d->m_intPair;
} }
StringList StringList MP4::Item::toStringList() const {
MP4::Item::toStringList() const {
return d->m_stringList; return d->m_stringList;
} }
ByteVectorList ByteVectorList MP4::Item::toByteVectorList() const {
MP4::Item::toByteVectorList() const {
return d->m_byteVectorList; return d->m_byteVectorList;
} }
MP4::CoverArtList MP4::CoverArtList MP4::Item::toCoverArtList() const {
MP4::Item::toCoverArtList() const {
return d->m_coverArtList; return d->m_coverArtList;
} }

View File

@@ -32,7 +32,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace MP4 { namespace MP4 {
class TAGLIB_EXPORT Item { class TAGLIB_EXPORT Item {
@@ -45,13 +44,13 @@ class TAGLIB_EXPORT Item {
Item(const Item &item); Item(const Item &item);
/*! /*!
* Copies the contents of \a item into this Item. * Copies the contents of \a item into this Item.
*/ */
Item &operator=(const Item &item); Item &operator=(const Item &item);
/*! /*!
* Exchanges the content of the Item by the content of \a item. * Exchanges the content of the Item by the content of \a item.
*/ */
void swap(Item &item); void swap(Item &item);
~Item(); ~Item();
@@ -87,7 +86,6 @@ class TAGLIB_EXPORT Item {
}; };
} // namespace MP4 } // namespace MP4
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -54,8 +54,7 @@ class MP4::Properties::PropertiesPrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style), MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
d(new PropertiesPrivate()) {
read(file, atoms); read(file, atoms);
} }
@@ -71,10 +70,6 @@ int MP4::Properties::sampleRate() const {
return d->sampleRate; return d->sampleRate;
} }
int MP4::Properties::length() const {
return lengthInSeconds();
}
int MP4::Properties::lengthInSeconds() const { int MP4::Properties::lengthInSeconds() const {
return d->length / 1000; return d->length / 1000;
} }
@@ -105,13 +100,14 @@ MP4::Properties::codec() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void MP4::Properties::read(File *file, Atoms *atoms) { void MP4::Properties::read(File *file, Atoms *atoms) {
MP4::Atom *moov = atoms->find("moov"); MP4::Atom *moov = atoms->find("moov");
if (!moov) { if (!moov) {
debug("MP4: Atom 'moov' not found"); debug("MP4: Atom 'moov' not found");
return; return;
} }
MP4::Atom *trak = 0; MP4::Atom *trak = nullptr;
ByteVector data; ByteVector data;
const MP4::AtomList trakList = moov->findall("trak"); const MP4::AtomList trakList = moov->findall("trak");
@@ -127,7 +123,7 @@ void MP4::Properties::read(File *file, Atoms *atoms) {
if (data.containsAt("soun", 16)) { if (data.containsAt("soun", 16)) {
break; break;
} }
trak = 0; trak = nullptr;
} }
if (!trak) { if (!trak) {
debug("MP4: No audio tracks"); debug("MP4: No audio tracks");
@@ -207,4 +203,5 @@ void MP4::Properties::read(File *file, Atoms *atoms) {
if (drms) { if (drms) {
d->encrypted = true; d->encrypted = true;
} }
} }

View File

@@ -31,7 +31,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace MP4 { namespace MP4 {
class Atoms; class Atoms;
@@ -50,60 +49,49 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
virtual ~Properties(); virtual ~Properties();
/*! /*!
* Returns the length of the file in seconds. The length is rounded down to * Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
* the nearest whole second. *
* * \see lengthInMilliseconds()
* \note This method is just an alias of lengthInSeconds(). */
*
* \deprecated
*/
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual // BIC: make virtual
int lengthInSeconds() const; int lengthInSeconds() const;
/*! /*!
* Returns the length of the file in milliseconds. * Returns the length of the file in milliseconds.
* *
* \see lengthInSeconds() * \see lengthInSeconds()
*/ */
// BIC: make virtual // BIC: make virtual
int lengthInMilliseconds() const; int lengthInMilliseconds() const;
/*! /*!
* Returns the average bit rate of the file in kb/s. * Returns the average bit rate of the file in kb/s.
*/ */
virtual int bitrate() const; virtual int bitrate() const;
/*! /*!
* Returns the sample rate in Hz. * Returns the sample rate in Hz.
*/ */
virtual int sampleRate() const; virtual int sampleRate() const;
/*! /*!
* Returns the number of audio channels. * Returns the number of audio channels.
*/ */
virtual int channels() const; virtual int channels() const;
/*! /*!
* Returns the number of bits per audio sample. * Returns the number of bits per audio sample.
*/ */
virtual int bitsPerSample() const; virtual int bitsPerSample() const;
/*! /*!
* Returns whether or not the file is encrypted. * Returns whether or not the file is encrypted.
*/ */
bool isEncrypted() const; bool isEncrypted() const;
/*! /*!
* Returns the codec used in the file. * Returns the codec used in the file.
*/ */
Codec codec() const; Codec codec() const;
private: private:
@@ -114,7 +102,6 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
}; };
} // namespace MP4 } // namespace MP4
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -34,18 +34,17 @@ using namespace Strawberry_TagLib::TagLib;
class MP4::Tag::TagPrivate { class MP4::Tag::TagPrivate {
public: public:
TagPrivate() : file(0), TagPrivate() : file(nullptr), atoms(nullptr) {}
atoms(0) {}
Strawberry_TagLib::TagLib::File *file; Strawberry_TagLib::TagLib::File *file;
Atoms *atoms; Atoms *atoms;
ItemMap items; ItemMap items;
}; };
MP4::Tag::Tag() : d(new TagPrivate()) { MP4::Tag::Tag() : d(new TagPrivate()) {}
}
MP4::Tag::Tag(Strawberry_TagLib::TagLib::File *file, MP4::Atoms *atoms) : d(new TagPrivate()) { MP4::Tag::Tag(Strawberry_TagLib::TagLib::File *file, MP4::Atoms *atoms) : d(new TagPrivate()) {
d->file = file; d->file = file;
d->atoms = atoms; d->atoms = atoms;
@@ -113,8 +112,8 @@ MP4::Tag::~Tag() {
delete d; delete d;
} }
MP4::AtomDataList MP4::AtomDataList MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
AtomDataList result; AtomDataList result;
ByteVector data = d->file->readBlock(atom->length - 8); ByteVector data = d->file->readBlock(atom->length - 8);
int i = 0; int i = 0;
@@ -152,47 +151,58 @@ MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
i++; i++;
} }
return result; return result;
} }
ByteVectorList ByteVectorList MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
AtomDataList data = parseData2(atom, expectedFlags, freeForm); AtomDataList data = parseData2(atom, expectedFlags, freeForm);
ByteVectorList result; ByteVectorList result;
for (AtomDataList::ConstIterator it = data.begin(); it != data.end(); ++it) { for (AtomDataList::ConstIterator it = data.begin(); it != data.end(); ++it) {
result.append(it->data); result.append(it->data);
} }
return result; return result;
} }
void MP4::Tag::parseInt(const MP4::Atom *atom) { void MP4::Tag::parseInt(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
addItem(atom->name, (int)data[0].toShort()); addItem(atom->name, (int)data[0].toShort());
} }
} }
void MP4::Tag::parseUInt(const MP4::Atom *atom) { void MP4::Tag::parseUInt(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
addItem(atom->name, data[0].toUInt()); addItem(atom->name, data[0].toUInt());
} }
} }
void MP4::Tag::parseLongLong(const MP4::Atom *atom) { void MP4::Tag::parseLongLong(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
addItem(atom->name, data[0].toLongLong()); addItem(atom->name, data[0].toLongLong());
} }
} }
void MP4::Tag::parseByte(const MP4::Atom *atom) { void MP4::Tag::parseByte(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
addItem(atom->name, static_cast<unsigned char>(data[0].at(0))); addItem(atom->name, static_cast<unsigned char>(data[0].at(0)));
} }
} }
void MP4::Tag::parseGnre(const MP4::Atom *atom) { void MP4::Tag::parseGnre(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
int idx = (int)data[0].toShort(); int idx = (int)data[0].toShort();
@@ -200,26 +210,32 @@ void MP4::Tag::parseGnre(const MP4::Atom *atom) {
addItem("\251gen", StringList(ID3v1::genre(idx - 1))); addItem("\251gen", StringList(ID3v1::genre(idx - 1)));
} }
} }
} }
void MP4::Tag::parseIntPair(const MP4::Atom *atom) { void MP4::Tag::parseIntPair(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
const int a = data[0].toShort(2U); const int a = data[0].toShort(2U);
const int b = data[0].toShort(4U); const int b = data[0].toShort(4U);
addItem(atom->name, MP4::Item(a, b)); addItem(atom->name, MP4::Item(a, b));
} }
} }
void MP4::Tag::parseBool(const MP4::Atom *atom) { void MP4::Tag::parseBool(const MP4::Atom *atom) {
ByteVectorList data = parseData(atom); ByteVectorList data = parseData(atom);
if (!data.isEmpty()) { if (!data.isEmpty()) {
bool value = data[0].size() ? data[0][0] != '\0' : false; bool value = data[0].size() ? data[0][0] != '\0' : false;
addItem(atom->name, value); addItem(atom->name, value);
} }
} }
void MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) { void MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) {
ByteVectorList data = parseData(atom, expectedFlags); ByteVectorList data = parseData(atom, expectedFlags);
if (!data.isEmpty()) { if (!data.isEmpty()) {
StringList value; StringList value;
@@ -228,9 +244,11 @@ void MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) {
} }
addItem(atom->name, value); addItem(atom->name, value);
} }
} }
void MP4::Tag::parseFreeForm(const MP4::Atom *atom) { void MP4::Tag::parseFreeForm(const MP4::Atom *atom) {
AtomDataList data = parseData2(atom, -1, true); AtomDataList data = parseData2(atom, -1, true);
if (data.size() > 2) { if (data.size() > 2) {
AtomDataList::ConstIterator itBegin = data.begin(); AtomDataList::ConstIterator itBegin = data.begin();
@@ -267,9 +285,11 @@ void MP4::Tag::parseFreeForm(const MP4::Atom *atom) {
addItem(name, item); addItem(name, item);
} }
} }
} }
void MP4::Tag::parseCovr(const MP4::Atom *atom) { void MP4::Tag::parseCovr(const MP4::Atom *atom) {
MP4::CoverArtList value; MP4::CoverArtList value;
ByteVector data = d->file->readBlock(atom->length - 8); ByteVector data = d->file->readBlock(atom->length - 8);
unsigned int pos = 0; unsigned int pos = 0;
@@ -299,106 +319,117 @@ void MP4::Tag::parseCovr(const MP4::Atom *atom) {
} }
if (!value.isEmpty()) if (!value.isEmpty())
addItem(atom->name, value); addItem(atom->name, value);
} }
ByteVector ByteVector MP4::Tag::padIlst(const ByteVector &data, int length) const {
MP4::Tag::padIlst(const ByteVector &data, int length) const {
if (length == -1) { if (length == -1) {
length = ((data.size() + 1023) & ~1023) - data.size(); length = ((data.size() + 1023) & ~1023) - data.size();
} }
return renderAtom("free", ByteVector(length, '\1')); return renderAtom("free", ByteVector(length, '\1'));
} }
ByteVector ByteVector MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const {
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const {
return ByteVector::fromUInt(data.size() + 8) + name + data; return ByteVector::fromUInt(data.size() + 8) + name + data;
} }
ByteVector ByteVector MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const {
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const {
ByteVector result; ByteVector result;
for (ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) { for (ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) {
result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + *it)); result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + *it));
} }
return renderAtom(name, result); return renderAtom(name, result);
} }
ByteVector ByteVector MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector(1, item.toBool() ? '\1' : '\0')); data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
return renderData(name, TypeInteger, data); return renderData(name, TypeInteger, data);
} }
ByteVector ByteVector MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector::fromShort(item.toInt())); data.append(ByteVector::fromShort(item.toInt()));
return renderData(name, TypeInteger, data); return renderData(name, TypeInteger, data);
} }
ByteVector ByteVector MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector::fromUInt(item.toUInt())); data.append(ByteVector::fromUInt(item.toUInt()));
return renderData(name, TypeInteger, data); return renderData(name, TypeInteger, data);
} }
ByteVector ByteVector MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector::fromLongLong(item.toLongLong())); data.append(ByteVector::fromLongLong(item.toLongLong()));
return renderData(name, TypeInteger, data); return renderData(name, TypeInteger, data);
} }
ByteVector ByteVector MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector(1, item.toByte())); data.append(ByteVector(1, item.toByte()));
return renderData(name, TypeInteger, data); return renderData(name, TypeInteger, data);
} }
ByteVector ByteVector MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector(2, '\0') + data.append(ByteVector(2, '\0') +
ByteVector::fromShort(item.toIntPair().first) + ByteVector::fromShort(item.toIntPair().first) +
ByteVector::fromShort(item.toIntPair().second) + ByteVector::fromShort(item.toIntPair().second) +
ByteVector(2, '\0')); ByteVector(2, '\0'));
return renderData(name, TypeImplicit, data); return renderData(name, TypeImplicit, data);
} }
ByteVector ByteVector MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4::Item &item) const {
ByteVectorList data; ByteVectorList data;
data.append(ByteVector(2, '\0') + data.append(ByteVector(2, '\0') +
ByteVector::fromShort(item.toIntPair().first) + ByteVector::fromShort(item.toIntPair().first) +
ByteVector::fromShort(item.toIntPair().second)); ByteVector::fromShort(item.toIntPair().second));
return renderData(name, TypeImplicit, data); return renderData(name, TypeImplicit, data);
} }
ByteVector ByteVector MP4::Tag::renderText(const ByteVector &name, const MP4::Item &item, int flags) const {
MP4::Tag::renderText(const ByteVector &name, const MP4::Item &item, int flags) const {
ByteVectorList data; ByteVectorList data;
StringList value = item.toStringList(); StringList value = item.toStringList();
for (StringList::ConstIterator it = value.begin(); it != value.end(); ++it) { for (StringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
data.append(it->data(String::UTF8)); data.append(it->data(String::UTF8));
} }
return renderData(name, flags, data); return renderData(name, flags, data);
} }
ByteVector ByteVector MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const {
MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const {
ByteVector data; ByteVector data;
MP4::CoverArtList value = item.toCoverArtList(); MP4::CoverArtList value = item.toCoverArtList();
for (MP4::CoverArtList::ConstIterator it = value.begin(); it != value.end(); ++it) { for (MP4::CoverArtList::ConstIterator it = value.begin(); it != value.end(); ++it) {
data.append(renderAtom("data", ByteVector::fromUInt(it->format()) + ByteVector(4, '\0') + it->data())); data.append(renderAtom("data", ByteVector::fromUInt(it->format()) + ByteVector(4, '\0') + it->data()));
} }
return renderAtom(name, data); return renderAtom(name, data);
} }
ByteVector ByteVector MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const {
MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const {
StringList header = StringList::split(name, ":"); StringList header = StringList::split(name, ":");
if (header.size() != 3) { if (header.size() != 3) {
debug("MP4: Invalid free-form item name \"" + name + "\""); debug("MP4: Invalid free-form item name \"" + name + "\"");
@@ -429,9 +460,11 @@ MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const {
} }
} }
return renderAtom("----", data); return renderAtom("----", data);
} }
bool MP4::Tag::save() { bool MP4::Tag::save() {
ByteVector data; ByteVector data;
for (MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) { for (MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
const String name = it->first; const String name = it->first;
@@ -496,9 +529,11 @@ bool MP4::Tag::save() {
} }
return true; return true;
} }
void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) { void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) {
if (static_cast<int>(path.size()) <= ignore) if (static_cast<int>(path.size()) <= ignore)
return; return;
@@ -525,6 +560,7 @@ void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) {
} }
void MP4::Tag::updateOffsets(long delta, long offset) { void MP4::Tag::updateOffsets(long delta, long offset) {
MP4::Atom *moov = d->atoms->find("moov"); MP4::Atom *moov = d->atoms->find("moov");
if (moov) { if (moov) {
MP4::AtomList stco = moov->findall("stco", true); MP4::AtomList stco = moov->findall("stco", true);
@@ -591,9 +627,11 @@ void MP4::Tag::updateOffsets(long delta, long offset) {
} }
} }
} }
} }
void MP4::Tag::saveNew(ByteVector data) { void MP4::Tag::saveNew(ByteVector data) {
data = renderAtom("meta", ByteVector(4, '\0') + renderAtom("hdlr", ByteVector(8, '\0') + ByteVector("mdirappl") + ByteVector(9, '\0')) + data + padIlst(data)); data = renderAtom("meta", ByteVector(4, '\0') + renderAtom("hdlr", ByteVector(8, '\0') + ByteVector("mdirappl") + ByteVector(9, '\0')) + data + padIlst(data));
AtomList path = d->atoms->path("moov", "udta"); AtomList path = d->atoms->path("moov", "udta");
@@ -612,9 +650,11 @@ void MP4::Tag::saveNew(ByteVector data) {
d->file->seek(offset); d->file->seek(offset);
path.back()->children.prepend(new Atom(d->file)); path.back()->children.prepend(new Atom(d->file));
} }
void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) { void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) {
AtomList::ConstIterator it = path.end(); AtomList::ConstIterator it = path.end();
MP4::Atom *ilst = *(--it); MP4::Atom *ilst = *(--it);
@@ -660,52 +700,46 @@ void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) {
updateParents(path, delta, 1); updateParents(path, delta, 1);
updateOffsets(delta, offset); updateOffsets(delta, offset);
} }
} }
String String MP4::Tag::title() const {
MP4::Tag::title() const {
if (d->items.contains("\251nam")) if (d->items.contains("\251nam"))
return d->items["\251nam"].toStringList().toString(", "); return d->items["\251nam"].toStringList().toString(", ");
return String(); return String();
} }
String String MP4::Tag::artist() const {
MP4::Tag::artist() const {
if (d->items.contains("\251ART")) if (d->items.contains("\251ART"))
return d->items["\251ART"].toStringList().toString(", "); return d->items["\251ART"].toStringList().toString(", ");
return String(); return String();
} }
String String MP4::Tag::album() const {
MP4::Tag::album() const {
if (d->items.contains("\251alb")) if (d->items.contains("\251alb"))
return d->items["\251alb"].toStringList().toString(", "); return d->items["\251alb"].toStringList().toString(", ");
return String(); return String();
} }
String String MP4::Tag::comment() const {
MP4::Tag::comment() const {
if (d->items.contains("\251cmt")) if (d->items.contains("\251cmt"))
return d->items["\251cmt"].toStringList().toString(", "); return d->items["\251cmt"].toStringList().toString(", ");
return String(); return String();
} }
String String MP4::Tag::genre() const {
MP4::Tag::genre() const {
if (d->items.contains("\251gen")) if (d->items.contains("\251gen"))
return d->items["\251gen"].toStringList().toString(", "); return d->items["\251gen"].toStringList().toString(", ");
return String(); return String();
} }
unsigned int unsigned int MP4::Tag::year() const {
MP4::Tag::year() const {
if (d->items.contains("\251day")) if (d->items.contains("\251day"))
return d->items["\251day"].toStringList().toString().toInt(); return d->items["\251day"].toStringList().toString().toInt();
return 0; return 0;
} }
unsigned int unsigned int MP4::Tag::track() const {
MP4::Tag::track() const {
if (d->items.contains("trkn")) if (d->items.contains("trkn"))
return d->items["trkn"].toIntPair().first; return d->items["trkn"].toIntPair().first;
return 0; return 0;
@@ -732,31 +766,31 @@ void MP4::Tag::setGenre(const String &value) {
} }
void MP4::Tag::setYear(unsigned int value) { void MP4::Tag::setYear(unsigned int value) {
if (value == 0) { if (value == 0) {
d->items.erase("\251day"); d->items.erase("\251day");
} }
else { else {
d->items["\251day"] = StringList(String::number(value)); d->items["\251day"] = StringList(String::number(value));
} }
} }
void MP4::Tag::setTrack(unsigned int value) { void MP4::Tag::setTrack(unsigned int value) {
if (value == 0) { if (value == 0) {
d->items.erase("trkn"); d->items.erase("trkn");
} }
else { else {
d->items["trkn"] = MP4::Item(value, 0); d->items["trkn"] = MP4::Item(value, 0);
} }
} }
bool MP4::Tag::isEmpty() const { bool MP4::Tag::isEmpty() const {
return d->items.isEmpty(); return d->items.isEmpty();
} }
MP4::ItemMap &MP4::Tag::itemListMap() {
return d->items;
}
const MP4::ItemMap &MP4::Tag::itemMap() const { const MP4::ItemMap &MP4::Tag::itemMap() const {
return d->items; return d->items;
} }
@@ -835,16 +869,19 @@ const char *keyTranslation[][2] = {
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]); const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
String translateKey(const String &key) { String translateKey(const String &key) {
for (size_t i = 0; i < keyTranslationSize; ++i) { for (size_t i = 0; i < keyTranslationSize; ++i) {
if (key == keyTranslation[i][0]) if (key == keyTranslation[i][0])
return keyTranslation[i][1]; return keyTranslation[i][1];
} }
return String(); return String();
} }
} // namespace } // namespace
PropertyMap MP4::Tag::properties() const { PropertyMap MP4::Tag::properties() const {
PropertyMap props; PropertyMap props;
for (MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) { for (MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
const String key = translateKey(it->first); const String key = translateKey(it->first);
@@ -872,14 +909,18 @@ PropertyMap MP4::Tag::properties() const {
} }
} }
return props; return props;
} }
void MP4::Tag::removeUnsupportedProperties(const StringList &props) { void MP4::Tag::removeUnsupportedProperties(const StringList &props) {
for (StringList::ConstIterator it = props.begin(); it != props.end(); ++it) for (StringList::ConstIterator it = props.begin(); it != props.end(); ++it)
d->items.erase(*it); d->items.erase(*it);
} }
PropertyMap MP4::Tag::setProperties(const PropertyMap &props) { PropertyMap MP4::Tag::setProperties(const PropertyMap &props) {
static Map<String, String> reverseKeyMap; static Map<String, String> reverseKeyMap;
if (reverseKeyMap.isEmpty()) { if (reverseKeyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
@@ -928,13 +969,16 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props) {
} }
return ignoredProps; return ignoredProps;
} }
void MP4::Tag::addItem(const String &name, const Item &value) { void MP4::Tag::addItem(const String &name, const Item &value) {
if (!d->items.contains(name)) { if (!d->items.contains(name)) {
d->items.insert(name, value); d->items.insert(name, value);
} }
else { else {
debug("MP4: Ignoring duplicate atom \"" + name + "\""); debug("MP4: Ignoring duplicate atom \"" + name + "\"");
} }
} }

View File

@@ -37,13 +37,8 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace MP4 { namespace MP4 {
/*!
* \deprecated
*/
TAGLIB_DEPRECATED typedef Strawberry_TagLib::TagLib::Map<String, Item> ItemListMap;
typedef Strawberry_TagLib::TagLib::Map<String, Item> ItemMap; typedef Strawberry_TagLib::TagLib::Map<String, Item> ItemMap;
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
@@ -70,36 +65,29 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
virtual void setTrack(unsigned int value); virtual void setTrack(unsigned int value);
virtual bool isEmpty() const; virtual bool isEmpty() const;
/*! /*!
* \deprecated Use the item() and setItem() API instead * Returns a string-keyed map of the MP4::Items for this tag.
*/ */
TAGLIB_DEPRECATED ItemMap &itemListMap();
/*!
* Returns a string-keyed map of the MP4::Items for this tag.
*/
const ItemMap &itemMap() const; const ItemMap &itemMap() const;
/*! /*!
* \return The item, if any, corresponding to \a key. * \return The item, if any, corresponding to \a key.
*/ */
Item item(const String &key) const; Item item(const String &key) const;
/*! /*!
* Sets the value of \a key to \a value, overwriting any previous value. * Sets the value of \a key to \a value, overwriting any previous value.
*/ */
void setItem(const String &key, const Item &value); void setItem(const String &key, const Item &value);
/*! /*!
* Removes the entry with \a key from the tag, or does nothing if it does * Removes the entry with \a key from the tag, or does nothing if it does not exist.
* not exist. */
*/
void removeItem(const String &key); void removeItem(const String &key);
/*! /*!
* \return True if the tag contains an entry for \a key. * \return True if the tag contains an entry for \a key.
*/ */
bool contains(const String &key) const; bool contains(const String &key) const;
PropertyMap properties() const; PropertyMap properties() const;
@@ -107,10 +95,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
PropertyMap setProperties(const PropertyMap &properties); PropertyMap setProperties(const PropertyMap &properties);
private: private:
AtomDataList parseData2(const Atom *atom, int expectedFlags = -1, AtomDataList parseData2(const Atom *atom, int expectedFlags = -1, bool freeForm = false);
bool freeForm = false); ByteVectorList parseData(const Atom *atom, int expectedFlags = -1, bool freeForm = false);
ByteVectorList parseData(const Atom *atom, int expectedFlags = -1,
bool freeForm = false);
void parseText(const Atom *atom, int expectedFlags = 1); void parseText(const Atom *atom, int expectedFlags = 1);
void parseFreeForm(const Atom *atom); void parseFreeForm(const Atom *atom);
void parseInt(const Atom *atom); void parseInt(const Atom *atom);
@@ -124,10 +110,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
ByteVector padIlst(const ByteVector &data, int length = -1) const; ByteVector padIlst(const ByteVector &data, int length = -1) const;
ByteVector renderAtom(const ByteVector &name, const ByteVector &data) const; ByteVector renderAtom(const ByteVector &name, const ByteVector &data) const;
ByteVector renderData(const ByteVector &name, int flags, ByteVector renderData(const ByteVector &name, int flags, const ByteVectorList &data) const;
const ByteVectorList &data) const; ByteVector renderText(const ByteVector &name, const Item &item, int flags = TypeUTF8) const;
ByteVector renderText(const ByteVector &name, const Item &item,
int flags = TypeUTF8) const;
ByteVector renderFreeForm(const String &name, const Item &item) const; ByteVector renderFreeForm(const String &name, const Item &item) const;
ByteVector renderBool(const ByteVector &name, const Item &item) const; ByteVector renderBool(const ByteVector &name, const Item &item) const;
ByteVector renderInt(const ByteVector &name, const Item &item) const; ByteVector renderInt(const ByteVector &name, const Item &item) const;
@@ -151,7 +135,6 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
}; };
} // namespace MP4 } // namespace MP4
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -48,10 +48,10 @@ class MPC::File::FilePrivate {
FilePrivate() : APELocation(-1), FilePrivate() : APELocation(-1),
APESize(0), APESize(0),
ID3v1Location(-1), ID3v1Location(-1),
ID3v2Header(0), ID3v2Header(nullptr),
ID3v2Location(-1), ID3v2Location(-1),
ID3v2Size(0), ID3v2Size(0),
properties(0) {} properties(nullptr) {}
~FilePrivate() { ~FilePrivate() {
delete ID3v2Header; delete ID3v2Header;
@@ -77,27 +77,31 @@ class MPC::File::FilePrivate {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool MPC::File::isSupported(IOStream *stream) { bool MPC::File::isSupported(IOStream *stream) {
// A newer MPC file has to start with "MPCK" or "MP+", but older files don't // A newer MPC file has to start with "MPCK" or "MP+", but older files don't
// have keys to do a quick check. // have keys to do a quick check.
const ByteVector id = Utils::readHeader(stream, 4, false); const ByteVector id = Utils::readHeader(stream, 4, false);
return (id == "MPCK" || id.startsWith("MP+")); return (id == "MPCK" || id.startsWith("MP+"));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
d(new FilePrivate()) {
if (isOpen()) if (isOpen())
read(readProperties); read(readProperties);
} }
MPC::File::~File() { MPC::File::~File() {
@@ -128,6 +132,7 @@ MPC::Properties *MPC::File::audioProperties() const {
} }
bool MPC::File::save() { bool MPC::File::save() {
if (readOnly()) { if (readOnly()) {
debug("MPC::File::save() -- File is read only."); debug("MPC::File::save() -- File is read only.");
return false; return false;
@@ -211,6 +216,7 @@ bool MPC::File::save() {
} }
return true; return true;
} }
ID3v1::Tag *MPC::File::ID3v1Tag(bool create) { ID3v1::Tag *MPC::File::ID3v1Tag(bool create) {
@@ -222,23 +228,21 @@ APE::Tag *MPC::File::APETag(bool create) {
} }
void MPC::File::strip(int tags) { void MPC::File::strip(int tags) {
if (tags & ID3v1) if (tags & ID3v1)
d->tag.set(MPCID3v1Index, 0); d->tag.set(MPCID3v1Index, nullptr);
if (tags & APE) if (tags & APE)
d->tag.set(MPCAPEIndex, 0); d->tag.set(MPCAPEIndex, nullptr);
if (!ID3v1Tag()) if (!ID3v1Tag())
APETag(true); APETag(true);
if (tags & ID3v2) { if (tags & ID3v2) {
delete d->ID3v2Header; delete d->ID3v2Header;
d->ID3v2Header = 0; d->ID3v2Header = nullptr;
} }
}
void MPC::File::remove(int tags) {
strip(tags);
} }
bool MPC::File::hasID3v1Tag() const { bool MPC::File::hasID3v1Tag() const {
@@ -254,6 +258,7 @@ bool MPC::File::hasAPETag() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void MPC::File::read(bool readProperties) { void MPC::File::read(bool readProperties) {
// Look for an ID3v2 tag // Look for an ID3v2 tag
d->ID3v2Location = Utils::findID3v2(this); d->ID3v2Location = Utils::findID3v2(this);
@@ -307,4 +312,5 @@ void MPC::File::read(bool readProperties) {
d->properties = new Properties(this, streamLength); d->properties = new Properties(this, streamLength);
} }
} }

View File

@@ -49,31 +49,27 @@ class Tag;
//! An implementation of MPC metadata //! An implementation of MPC metadata
/*! /*!
* This is implementation of MPC metadata. * This is implementation of MPC metadata.
* *
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream properties from the file.
* properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped * ID3v2 tags are invalid in MPC-files, but will be skipped and ignored.
* and ignored. *
*/ */
namespace MPC { namespace MPC {
//! An implementation of TagLib::File with MPC specific methods //! An implementation of TagLib::File with MPC specific methods
/*! /*!
* This implements and provides an interface for MPC files to the * This implements and provides an interface for MPC files to the TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing the abstract TagLib::File API as well as providing some additional information specific to MPC files.
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * The only invalid tag combination supported is an ID3v1 tag after an APE tag.
* the abstract TagLib::File API as well as providing some additional */
* information specific to MPC files.
* The only invalid tag combination supported is an ID3v1 tag after an APE tag.
*/
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public: public:
/*! /*!
* This set of flags is used for various operations and is suitable for * This set of flags is used for various operations and is suitable for being OR-ed together.
* being OR-ed together. */
*/
enum TagTypes { enum TagTypes {
//! Empty set. Matches no tag types. //! Empty set. Matches no tag types.
NoTags = 0x0000, NoTags = 0x0000,
@@ -88,143 +84,124 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
}; };
/*! /*!
* Constructs an MPC file from \a file. If \a readProperties is true the * Constructs an MPC file from \a file.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note In the current implementation, \a propertiesStyle is ignored. * \note In the current implementation, \a propertiesStyle is ignored.
*/ */
File(FileName file, bool readProperties = true, File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Constructs an MPC file from \a stream. If \a readProperties is true the * Constructs an MPC file from \a stream.
* file's audio properties will also be read. * If \a readProperties is true the file's audio properties will also be read.
* *
* \note TagLib will *not* take ownership of the stream, the caller is * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
* responsible for deleting it after the File object. *
* * \note In the current implementation, \a propertiesStyle is ignored.
* \note In the current implementation, \a propertiesStyle is ignored. */
*/ File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*! /*!
* Destroys this instance of the File. * Destroys this instance of the File.
*/ */
virtual ~File(); virtual ~File();
/*! /*!
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag * Returns the Tag for this file.
* or a combination of the two. * This will be an APE tag, an ID3v1 tag or a combination of the two.
*/ */
virtual Strawberry_TagLib::TagLib::Tag *tag() const; virtual Strawberry_TagLib::TagLib::Tag *tag() const;
/*! /*!
* Implements the unified property interface -- export function. * Implements the unified property interface -- export function.
* If the file contains both an APE and an ID3v1 tag, only the APE * If the file contains both an APE and an ID3v1 tag, only the APE tag will be converted to the PropertyMap.
* tag will be converted to the PropertyMap. */
*/
PropertyMap properties() const; PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties); void removeUnsupportedProperties(const StringList &properties);
/*! /*!
* Implements the unified property interface -- import function. * Implements the unified property interface -- import function.
* Affects only the APEv2 tag which will be created if necessary. * Affects only the APEv2 tag which will be created if necessary.
* If an ID3v1 tag exists, it will be updated as well. * If an ID3v1 tag exists, it will be updated as well.
*/ */
PropertyMap setProperties(const PropertyMap &); PropertyMap setProperties(const PropertyMap &);
/*! /*!
* Returns the MPC::Properties for this file. If no audio properties * Returns the MPC::Properties for this file.
* were read then this will return a null pointer. * If no audio properties were read then this will return a null pointer.
*/ */
virtual Properties *audioProperties() const; virtual Properties *audioProperties() const;
/*! /*!
* Saves the file. * Saves the file.
* *
* This returns true if the save was successful. * This returns true if the save was successful.
*/ */
virtual bool save(); virtual bool save();
/*! /*!
* Returns a pointer to the ID3v1 tag of the file. * Returns a pointer to the ID3v1 tag of the file.
* *
* If \a create is false (the default) this returns a null pointer * If \a create is false (the default) this returns a null pointer if there is no valid APE tag.
* if there is no valid APE tag. If \a create is true it will create * If \a create is true it will create an APE tag if one does not exist and returns a valid pointer.
* an APE tag if one does not exist and returns a valid pointer. *
* * \note This may return a valid pointer regardless of whether or not the file on disk has an ID3v1 tag.
* \note This may return a valid pointer regardless of whether or not the * Use hasID3v1Tag() to check if the file on disk actually has an ID3v1 tag.
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file *
* on disk actually has an ID3v1 tag. * \note The Tag <b>is still</b> owned by the MPEG::File and should not be deleted by the user.
* * It will be deleted when the file (object) is destroyed.
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be *
* deleted by the user. It will be deleted when the file (object) is * \see hasID3v1Tag()
* destroyed. */
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false); ID3v1::Tag *ID3v1Tag(bool create = false);
/*! /*!
* Returns a pointer to the APE tag of the file. * Returns a pointer to the APE tag of the file.
* *
* If \a create is false (the default) this may return a null pointer * If \a create is false (the default) this may return a null pointer
* if there is no valid APE tag. If \a create is true it will create * if there is no valid APE tag.
* an APE tag if one does not exist and returns a valid pointer. If * If \a create is true it will create an APE tag if one does not exist and returns a valid pointer.
* there already be an ID3v1 tag, the new APE tag will be placed before it. * If there already be an ID3v1 tag, the new APE tag will be placed before it.
* *
* \note This may return a valid pointer regardless of whether or not the * \note This may return a valid pointer regardless of whether or not the file on disk has an APE tag.
* file on disk has an APE tag. Use hasAPETag() to check if the file * Use hasAPETag() to check if the file on disk actually has an APE tag.
* on disk actually has an APE tag. *
* * \note The Tag <b>is still</b> owned by the MPEG::File and should not be deleted by the user.
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be * It will be deleted when the file (object) is destroyed.
* deleted by the user. It will be deleted when the file (object) is *
* destroyed. * \see hasAPETag()
* */
* \see hasAPETag()
*/
APE::Tag *APETag(bool create = false); APE::Tag *APETag(bool create = false);
/*! /*!
* This will remove the tags that match the OR-ed together TagTypes from the * This will remove the tags that match the OR-ed together TagTypes from the file. By default it removes all tags.
* file. By default it removes all tags. *
* * \warning This will also invalidate pointers to the tags as their memory will be freed.
* \warning This will also invalidate pointers to the tags *
* as their memory will be freed. * \note In order to make the removal permanent save() still needs to be called.
* */
* \note In order to make the removal permanent save() still needs to be called.
*/
void strip(int tags = AllTags); void strip(int tags = AllTags);
/*! /*!
* \deprecated * Returns whether or not the file on disk actually has an ID3v1 tag.
* \see strip *
*/ * \see ID3v1Tag()
TAGLIB_DEPRECATED void remove(int tags = AllTags); */
/*!
* Returns whether or not the file on disk actually has an ID3v1 tag.
*
* \see ID3v1Tag()
*/
bool hasID3v1Tag() const; bool hasID3v1Tag() const;
/*! /*!
* Returns whether or not the file on disk actually has an APE tag. * Returns whether or not the file on disk actually has an APE tag.
* *
* \see APETag() * \see APETag()
*/ */
bool hasAPETag() const; bool hasAPETag() const;
/*! /*!
* Returns whether or not the given \a stream can be opened as an MPC * Returns whether or not the given \a stream can be opened as an MPC file.
* file. *
* * \note This method is designed to do a quick check. The result may not necessarily be correct.
* \note This method is designed to do a quick check. The result may */
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream); static bool isSupported(IOStream *stream);
private: private:

View File

@@ -64,13 +64,12 @@ class MPC::Properties::PropertiesPrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style), MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
d(new PropertiesPrivate()) {
readSV7(data, streamLength); readSV7(data, streamLength);
} }
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style), MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
d(new PropertiesPrivate()) {
ByteVector magic = file->readBlock(4); ByteVector magic = file->readBlock(4);
if (magic == "MPCK") { if (magic == "MPCK") {
// Musepack version 8 // Musepack version 8
@@ -80,16 +79,13 @@ MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : Au
// Musepack version 7 or older, fixed size header // Musepack version 7 or older, fixed size header
readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength); readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength);
} }
} }
MPC::Properties::~Properties() { MPC::Properties::~Properties() {
delete d; delete d;
} }
int MPC::Properties::length() const {
return lengthInSeconds();
}
int MPC::Properties::lengthInSeconds() const { int MPC::Properties::lengthInSeconds() const {
return d->length / 1000; return d->length / 1000;
} }
@@ -144,6 +140,7 @@ int MPC::Properties::albumPeak() const {
namespace { namespace {
unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) { unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) {
sizeLength = 0; sizeLength = 0;
eof = false; eof = false;
@@ -160,19 +157,26 @@ unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) {
tmp = b[0]; tmp = b[0];
size = (size << 7) | (tmp & 0x7F); size = (size << 7) | (tmp & 0x7F);
sizeLength++; sizeLength++;
} while ((tmp & 0x80)); }
while ((tmp & 0x80));
return size; return size;
} }
unsigned long readSize(const ByteVector &data, unsigned int &pos) { unsigned long readSize(const ByteVector &data, unsigned int &pos) {
unsigned char tmp; unsigned char tmp;
unsigned long size = 0; unsigned long size = 0;
do { do {
tmp = data[pos++]; tmp = data[pos++];
size = (size << 7) | (tmp & 0x7F); size = (size << 7) | (tmp & 0x7F);
} while ((tmp & 0x80) && (pos < data.size())); }
while ((tmp & 0x80) && (pos < data.size()));
return size; return size;
} }
// This array looks weird, but the same as original MusePack code found at: // This array looks weird, but the same as original MusePack code found at:
@@ -181,6 +185,7 @@ const unsigned short sftable[8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 };
} // namespace } // namespace
void MPC::Properties::readSV8(File *file, long streamLength) { void MPC::Properties::readSV8(File *file, long streamLength) {
bool readSH = false, readRG = false; bool readSH = false, readRG = false;
while (!readSH && !readRG) { while (!readSH && !readRG) {
@@ -269,9 +274,11 @@ void MPC::Properties::readSV8(File *file, long streamLength) {
file->seek(dataSize, File::Current); file->seek(dataSize, File::Current);
} }
} }
} }
void MPC::Properties::readSV7(const ByteVector &data, long streamLength) { void MPC::Properties::readSV7(const ByteVector &data, long streamLength) {
if (data.startsWith("MP+")) { if (data.startsWith("MP+")) {
d->version = data[3] & 15; d->version = data[3] & 15;
if (d->version < 7) if (d->version < 7)
@@ -340,4 +347,5 @@ void MPC::Properties::readSV7(const ByteVector &data, long streamLength) {
if (d->bitrate == 0) if (d->bitrate == 0)
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5); d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
} }
} }

View File

@@ -41,105 +41,92 @@ static const unsigned int HeaderSize = 8 * 7;
//! An implementation of audio property reading for MPC //! An implementation of audio property reading for MPC
/*! /*!
* This reads the data from an MPC stream found in the AudioProperties * This reads the data from an MPC stream found in the AudioProperties API.
* API. */
*/
class TAGLIB_EXPORT Properties : public AudioProperties { class TAGLIB_EXPORT Properties : public AudioProperties {
public: public:
/*! /*!
* Create an instance of MPC::Properties with the data read from the * Create an instance of MPC::Properties with the data read from the ByteVector \a data.
* ByteVector \a data. *
* * This constructor is deprecated. It only works for MPC version up to 7.
* This constructor is deprecated. It only works for MPC version up to 7. */
*/
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
/*! /*!
* Create an instance of MPC::Properties with the data read directly * Create an instance of MPC::Properties with the data read directly from a MPC::File.
* from a MPC::File. */
*/
Properties(File *file, long streamLength, ReadStyle style = Average); Properties(File *file, long streamLength, ReadStyle style = Average);
/*! /*!
* Destroys this MPC::Properties instance. * Destroys this MPC::Properties instance.
*/ */
virtual ~Properties(); virtual ~Properties();
/*! /*!
* Returns the length of the file in seconds. The length is rounded down to * Returns the length of the file in seconds.
* the nearest whole second. * The length is rounded down to the nearest whole second.
* *
* \note This method is just an alias of lengthInSeconds(). * \see lengthInMilliseconds()
* */
* \deprecated
*/
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual // BIC: make virtual
int lengthInSeconds() const; int lengthInSeconds() const;
/*! /*!
* Returns the length of the file in milliseconds. * Returns the length of the file in milliseconds.
* *
* \see lengthInSeconds() * \see lengthInSeconds()
*/ */
// BIC: make virtual // BIC: make virtual
int lengthInMilliseconds() const; int lengthInMilliseconds() const;
/*! /*!
* Returns the average bit rate of the file in kb/s. * Returns the average bit rate of the file in kb/s.
*/ */
virtual int bitrate() const; virtual int bitrate() const;
/*! /*!
* Returns the sample rate in Hz. * Returns the sample rate in Hz.
*/ */
virtual int sampleRate() const; virtual int sampleRate() const;
/*! /*!
* Returns the number of audio channels. * Returns the number of audio channels.
*/ */
virtual int channels() const; virtual int channels() const;
/*! /*!
* Returns the version of the bitstream (SV4-SV8) * Returns the version of the bitstream (SV4-SV8)
*/ */
int mpcVersion() const; int mpcVersion() const;
unsigned int totalFrames() const; unsigned int totalFrames() const;
unsigned int sampleFrames() const; unsigned int sampleFrames() const;
/*! /*!
* Returns the track gain as an integer value, * Returns the track gain as an integer value,
* to convert to dB: trackGain in dB = 64.82 - (trackGain / 256) * to convert to dB: trackGain in dB = 64.82 - (trackGain / 256)
*/ */
int trackGain() const; int trackGain() const;
/*! /*!
* Returns the track peak as an integer value, * Returns the track peak as an integer value,
* to convert to dB: trackPeak in dB = trackPeak / 256 * to convert to dB: trackPeak in dB = trackPeak / 256
* to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768 * to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768
*/ */
int trackPeak() const; int trackPeak() const;
/*! /*!
* Returns the album gain as an integer value, * Returns the album gain as an integer value,
* to convert to dB: albumGain in dB = 64.82 - (albumGain / 256) * to convert to dB: albumGain in dB = 64.82 - (albumGain / 256)
*/ */
int albumGain() const; int albumGain() const;
/*! /*!
* Returns the album peak as an integer value, * Returns the album peak as an integer value,
* to convert to dB: albumPeak in dB = albumPeak / 256 * to convert to dB: albumPeak in dB = albumPeak / 256
* to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768 * to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768
*/ */
int albumPeak() const; int albumPeak() const;
private: private:

View File

@@ -226,35 +226,43 @@ const int genresSize = sizeof(genres) / sizeof(genres[0]);
} // namespace } // namespace
StringList ID3v1::genreList() { StringList ID3v1::genreList() {
StringList l; StringList l;
for (int i = 0; i < genresSize; i++) { for (int i = 0; i < genresSize; i++) {
l.append(genres[i]); l.append(genres[i]);
} }
return l; return l;
} }
ID3v1::GenreMap ID3v1::genreMap() { ID3v1::GenreMap ID3v1::genreMap() {
GenreMap m; GenreMap m;
for (int i = 0; i < genresSize; i++) { for (int i = 0; i < genresSize; i++) {
m.insert(genres[i], i); m.insert(genres[i], i);
} }
return m; return m;
} }
String ID3v1::genre(int i) { String ID3v1::genre(int i) {
if (i >= 0 && i < genresSize) if (i >= 0 && i < genresSize)
return String(genres[i]); // always make a copy return String(genres[i]); // always make a copy
else else
return String(); return String();
} }
int ID3v1::genreIndex(const String &name) { int ID3v1::genreIndex(const String &name) {
for (int i = 0; i < genresSize; ++i) { for (int i = 0; i < genresSize; ++i) {
if (name == genres[i]) if (name == genres[i])
return i; return i;
} }
return 255; return 255;
} }

View File

@@ -37,29 +37,25 @@ namespace ID3v1 {
typedef Map<String, int> GenreMap; typedef Map<String, int> GenreMap;
/*! /*!
* Returns the list of canonical ID3v1 genre names in the order that they * Returns the list of canonical ID3v1 genre names in the order that they are listed in the standard.
* are listed in the standard. */
*/
StringList TAGLIB_EXPORT genreList(); StringList TAGLIB_EXPORT genreList();
/*! /*!
* A "reverse mapping" that goes from the canonical ID3v1 genre name to the * A "reverse mapping" that goes from the canonical ID3v1 genre name to the respective genre number. genreMap()["Rock"] ==
* respective genre number. genreMap()["Rock"] == */
*/
GenreMap TAGLIB_EXPORT genreMap(); GenreMap TAGLIB_EXPORT genreMap();
/*! /*!
* Returns the name of the genre at \a index in the ID3v1 genre list. If * Returns the name of the genre at \a index in the ID3v1 genre list.
* \a index is out of range -- less than zero or greater than 191 -- a null * If \a index is out of range -- less than zero or greater than 191 -- a null string will be returned.
* string will be returned. */
*/
String TAGLIB_EXPORT genre(int index); String TAGLIB_EXPORT genre(int index);
/*! /*!
* Returns the genre index for the (case sensitive) genre \a name. If the * Returns the genre index for the (case sensitive) genre \a name.
* genre is not in the list 255 (which signifies an unknown genre in ID3v1) * If the genre is not in the list 255 (which signifies an unknown genre in ID3v1) will be returned.
* will be returned. */
*/
int TAGLIB_EXPORT genreIndex(const String &name); int TAGLIB_EXPORT genreIndex(const String &name);
} // namespace ID3v1 } // namespace ID3v1
} // namespace TagLib } // namespace TagLib

View File

@@ -39,7 +39,7 @@ const ID3v1::StringHandler *stringHandler = &defaultStringHandler;
class ID3v1::Tag::TagPrivate { class ID3v1::Tag::TagPrivate {
public: public:
TagPrivate() : file(0), TagPrivate() : file(nullptr),
tagOffset(0), tagOffset(0),
track(0), track(0),
genre(255) {} genre(255) {}
@@ -68,22 +68,22 @@ String ID3v1::StringHandler::parse(const ByteVector &data) const {
} }
ByteVector ID3v1::StringHandler::render(const String &s) const { ByteVector ID3v1::StringHandler::render(const String &s) const {
if (s.isLatin1()) if (s.isLatin1())
return s.data(String::Latin1); return s.data(String::Latin1);
else else
return ByteVector(); return ByteVector();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// public methods // public methods
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ID3v1::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), ID3v1::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), d(new TagPrivate()) {}
d(new TagPrivate()) {
} ID3v1::Tag::Tag(File *file, long tagOffset) : Strawberry_TagLib::TagLib::Tag(), d(new TagPrivate()) {
ID3v1::Tag::Tag(File *file, long tagOffset) : Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate()) {
d->file = file; d->file = file;
d->tagOffset = tagOffset; d->tagOffset = tagOffset;
@@ -95,6 +95,7 @@ ID3v1::Tag::~Tag() {
} }
ByteVector ID3v1::Tag::render() const { ByteVector ID3v1::Tag::render() const {
ByteVector data; ByteVector data;
data.append(fileIdentifier()); data.append(fileIdentifier());
@@ -108,6 +109,7 @@ ByteVector ID3v1::Tag::render() const {
data.append(char(d->genre)); data.append(char(d->genre));
return data; return data;
} }
ByteVector ID3v1::Tag::fileIdentifier() { ByteVector ID3v1::Tag::fileIdentifier() {
@@ -190,6 +192,7 @@ void ID3v1::Tag::setStringHandler(const StringHandler *handler) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ID3v1::Tag::read() { void ID3v1::Tag::read() {
if (d->file && d->file->isValid()) { if (d->file && d->file->isValid()) {
d->file->seek(d->tagOffset); d->file->seek(d->tagOffset);
// read the tag -- always 128 bytes // read the tag -- always 128 bytes
@@ -201,9 +204,11 @@ void ID3v1::Tag::read() {
else else
debug("ID3v1 tag is not valid or could not be read at the specified offset."); debug("ID3v1 tag is not valid or could not be read at the specified offset.");
} }
} }
void ID3v1::Tag::parse(const ByteVector &data) { void ID3v1::Tag::parse(const ByteVector &data) {
int offset = 3; int offset = 3;
d->title = stringHandler->parse(data.mid(offset, 30)); d->title = stringHandler->parse(data.mid(offset, 30));
@@ -235,4 +240,5 @@ void ID3v1::Tag::parse(const ByteVector &data) {
offset += 30; offset += 30;
d->genre = static_cast<unsigned char>(data[offset]); d->genre = static_cast<unsigned char>(data[offset]);
} }

View File

@@ -42,94 +42,86 @@ namespace ID3v1 {
//! A abstraction for the string to data encoding in ID3v1 tags. //! A abstraction for the string to data encoding in ID3v1 tags.
/*! /*!
* ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In * ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In practice it does not.
* practice it does not. TagLib by default only supports ISO-8859-1 data * TagLib by default only supports ISO-8859-1 data in ID3v1 tags.
* in ID3v1 tags. *
* * However by subclassing this class and reimplementing parse() and render() and setting your reimplementation as the default with
* However by subclassing this class and reimplementing parse() and render() * ID3v1::Tag::setStringHandler() you can define how you would like these transformations to be done.
* and setting your reimplementation as the default with *
* ID3v1::Tag::setStringHandler() you can define how you would like these * \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1 tags.
* transformations to be done. * Please consider disabling the writing of ID3v1 tags in the case that the data is not ISO-8859-1.
* *
* \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1 * \see ID3v1::Tag::setStringHandler()
* tags. Please consider disabling the writing of ID3v1 tags in the case */
* that the data is not ISO-8859-1.
*
* \see ID3v1::Tag::setStringHandler()
*/
class TAGLIB_EXPORT StringHandler { class TAGLIB_EXPORT StringHandler {
TAGLIB_IGNORE_MISSING_DESTRUCTOR TAGLIB_IGNORE_MISSING_DESTRUCTOR
public: public:
// BIC: Add virtual destructor. // BIC: Add virtual destructor.
StringHandler(); StringHandler();
/*! /*!
* Decode a string from \a data. The default implementation assumes that * Decode a string from \a data.
* \a data is an ISO-8859-1 (Latin1) character array. * The default implementation assumes that \a data is an ISO-8859-1 (Latin1) character array.
*/ */
virtual String parse(const ByteVector &data) const; virtual String parse(const ByteVector &data) const;
/*! /*!
* Encode a ByteVector with the data from \a s. The default implementation * Encode a ByteVector with the data from \a s.
* assumes that \a s is an ISO-8859-1 (Latin1) string. If the string is * The default implementation assumes that \a s is an ISO-8859-1 (Latin1) string.
* does not conform to ISO-8859-1, no value is written. * If the string is does not conform to ISO-8859-1, no value is written.
* *
* \warning It is recommended that you <b>not</b> override this method, but * \warning It is recommended that you <b>not</b> override this method, but
* instead do not write an ID3v1 tag in the case that the data is not * instead do not write an ID3v1 tag in the case that the data is not ISO-8859-1.
* ISO-8859-1. */
*/
virtual ByteVector render(const String &s) const; virtual ByteVector render(const String &s) const;
}; };
//! The main class in the ID3v1 implementation //! The main class in the ID3v1 implementation
/*! /*!
* This is an implementation of the ID3v1 format. ID3v1 is both the simplest * This is an implementation of the ID3v1 format.
* and most common of tag formats but is rather limited. Because of its * ID3v1 is both the simplest and most common of tag formats but is rather limited.
* pervasiveness and the way that applications have been written around the * Because of its pervasiveness and the way that applications have been written around the
* fields that it provides, the generic TagLib::Tag API is a mirror of what is * fields that it provides, the generic TagLib::Tag API is a mirror of what is provided by ID3v1.
* provided by ID3v1. *
* * ID3v1 tags should generally only contain Latin1 information.
* ID3v1 tags should generally only contain Latin1 information. However because * However because many applications do not follow this rule there is now support for overriding
* many applications do not follow this rule there is now support for overriding * the ID3v1 string handling using the ID3v1::StringHandler class.
* the ID3v1 string handling using the ID3v1::StringHandler class. Please see * Please see the documentation for that class for more information.
* the documentation for that class for more information. *
* * \see StringHandler
* \see StringHandler *
* * \note Most fields are truncated to a maximum of 28-30 bytes.
* \note Most fields are truncated to a maximum of 28-30 bytes. The * The truncation happens automatically when the tag is rendered.
* truncation happens automatically when the tag is rendered. */
*/
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public: public:
/*! /*!
* Create an ID3v1 tag with default values. * Create an ID3v1 tag with default values.
*/ */
Tag(); Tag();
/*! /*!
* Create an ID3v1 tag and parse the data in \a file starting at * Create an ID3v1 tag and parse the data in \a file starting at \a tagOffset.
* \a tagOffset. */
*/
Tag(File *file, long tagOffset); Tag(File *file, long tagOffset);
/*! /*!
* Destroys this Tag instance. * Destroys this Tag instance.
*/ */
virtual ~Tag(); virtual ~Tag();
/*! /*!
* Renders the in memory values to a ByteVector suitable for writing to * Renders the in memory values to a ByteVector suitable for writing to the file.
* the file. */
*/
ByteVector render() const; ByteVector render() const;
/*! /*!
* Returns the string "TAG" suitable for usage in locating the tag in a * Returns the string "TAG" suitable for usage in locating the tag in a file.
* file. */
*/
static ByteVector fileIdentifier(); static ByteVector fileIdentifier();
// Reimplementations. // Reimplementations.
@@ -151,41 +143,37 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
virtual void setTrack(unsigned int i); virtual void setTrack(unsigned int i);
/*! /*!
* Returns the genre in number. * Returns the genre in number.
* *
* \note Normally 255 indicates that this tag contains no genre. * \note Normally 255 indicates that this tag contains no genre.
*/ */
unsigned int genreNumber() const; unsigned int genreNumber() const;
/*! /*!
* Sets the genre in number to \a i. * Sets the genre in number to \a i.
* *
* \note Valid value is from 0 up to 255. Normally 255 indicates that * \note Valid value is from 0 up to 255. Normally 255 indicates that this tag contains no genre.
* this tag contains no genre. */
*/
void setGenreNumber(unsigned int i); void setGenreNumber(unsigned int i);
/*! /*!
* Sets the string handler that decides how the ID3v1 data will be * Sets the string handler that decides how the ID3v1 data will be converted to and from binary data.
* converted to and from binary data. * If the parameter \a handler is null, the previous handler is released and default ISO-8859-1 handler is restored.
* If the parameter \a handler is null, the previous handler is *
* released and default ISO-8859-1 handler is restored. * \note The caller is responsible for deleting the previous handler as needed after it is released.
* *
* \note The caller is responsible for deleting the previous handler * \see StringHandler
* as needed after it is released. */
*
* \see StringHandler
*/
static void setStringHandler(const StringHandler *handler); static void setStringHandler(const StringHandler *handler);
protected: protected:
/*! /*!
* Reads from the file specified in the constructor. * Reads from the file specified in the constructor.
*/ */
void read(); void read();
/*! /*!
* Pareses the body of the tag in \a data. * Pareses the body of the tag in \a data.
*/ */
void parse(const ByteVector &data); void parse(const ByteVector &data);
private: private:
@@ -195,6 +183,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
class TagPrivate; class TagPrivate;
TagPrivate *d; TagPrivate *d;
}; };
} // namespace ID3v1 } // namespace ID3v1
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -33,8 +33,7 @@ using namespace ID3v2;
class AttachedPictureFrame::AttachedPictureFramePrivate { class AttachedPictureFrame::AttachedPictureFramePrivate {
public: public:
AttachedPictureFramePrivate() : textEncoding(String::Latin1), AttachedPictureFramePrivate() : textEncoding(String::Latin1), type(AttachedPictureFrame::Other) {}
type(AttachedPictureFrame::Other) {}
String::Type textEncoding; String::Type textEncoding;
String mimeType; String mimeType;
@@ -47,12 +46,9 @@ class AttachedPictureFrame::AttachedPictureFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC"), AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC"), d(new AttachedPictureFramePrivate()) {}
d(new AttachedPictureFramePrivate()) {
}
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data), AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data), d(new AttachedPictureFramePrivate()) {
d(new AttachedPictureFramePrivate()) {
setData(data); setData(data);
} }
@@ -110,6 +106,7 @@ void AttachedPictureFrame::setPicture(const ByteVector &p) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void AttachedPictureFrame::parseFields(const ByteVector &data) { void AttachedPictureFrame::parseFields(const ByteVector &data) {
if (data.size() < 5) { if (data.size() < 5) {
debug("A picture frame must contain at least 5 bytes."); debug("A picture frame must contain at least 5 bytes.");
return; return;
@@ -130,9 +127,11 @@ void AttachedPictureFrame::parseFields(const ByteVector &data) {
d->description = readStringField(data, d->textEncoding, &pos); d->description = readStringField(data, d->textEncoding, &pos);
d->data = data.mid(pos); d->data = data.mid(pos);
} }
ByteVector AttachedPictureFrame::renderFields() const { ByteVector AttachedPictureFrame::renderFields() const {
ByteVector data; ByteVector data;
String::Type encoding = checkTextEncoding(d->description, d->textEncoding); String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
@@ -146,14 +145,14 @@ ByteVector AttachedPictureFrame::renderFields() const {
data.append(d->data); data.append(d->data);
return data; return data;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h), AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h), d(new AttachedPictureFramePrivate()) {
d(new AttachedPictureFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }
@@ -162,6 +161,7 @@ AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void AttachedPictureFrameV22::parseFields(const ByteVector &data) { void AttachedPictureFrameV22::parseFields(const ByteVector &data) {
if (data.size() < 5) { if (data.size() < 5) {
debug("A picture frame must contain at least 5 bytes."); debug("A picture frame must contain at least 5 bytes.");
return; return;
@@ -189,9 +189,11 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data) {
d->description = readStringField(data, d->textEncoding, &pos); d->description = readStringField(data, d->textEncoding, &pos);
d->data = data.mid(pos); d->data = data.mid(pos);
} }
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h) { AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h) {
// set v2.2 header to make fieldData work correctly // set v2.2 header to make fieldData work correctly
setHeader(h, true); setHeader(h, true);
@@ -201,4 +203,5 @@ AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header
Frame::Header *newHeader = new Frame::Header("APIC"); Frame::Header *newHeader = new Frame::Header("APIC");
newHeader->setFrameSize(h->frameSize()); newHeader->setFrameSize(h->frameSize());
setHeader(newHeader, true); setHeader(newHeader, true);
} }

View File

@@ -32,25 +32,23 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An ID3v2 attached picture frame implementation //! An ID3v2 attached picture frame implementation
/*! /*!
* This is an implementation of ID3v2 attached pictures. Pictures may be * This is an implementation of ID3v2 attached pictures.
* included in tags, one per APIC frame (but there may be multiple APIC * Pictures may be included in tags, one per APIC frame (but there may be multiple APIC frames in a single tag).
* frames in a single tag). These pictures are usually in either JPEG or * These pictures are usually in either JPEG or PNG format.
* PNG format. */
*/
class TAGLIB_EXPORT AttachedPictureFrame : public Frame { class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* This describes the function or content of the picture. * This describes the function or content of the picture.
*/ */
enum Type { enum Type {
//! A type not enumerated below //! A type not enumerated below
Other = 0x00, Other = 0x00,
@@ -97,108 +95,106 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
}; };
/*! /*!
* Constructs an empty picture frame. The description, content and text * Constructs an empty picture frame.
* encoding should be set manually. * The description, content and text encoding should be set manually.
*/ */
AttachedPictureFrame(); AttachedPictureFrame();
/*! /*!
* Constructs an AttachedPicture frame based on \a data. * Constructs an AttachedPicture frame based on \a data.
*/ */
explicit AttachedPictureFrame(const ByteVector &data); explicit AttachedPictureFrame(const ByteVector &data);
/*! /*!
* Destroys the AttahcedPictureFrame instance. * Destroys the AttahcedPictureFrame instance.
*/ */
virtual ~AttachedPictureFrame(); virtual ~AttachedPictureFrame();
/*! /*!
* Returns a string containing the description and mime-type * Returns a string containing the description and mime-type
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the text encoding used for the description. * Returns the text encoding used for the description.
* *
* \see setTextEncoding() * \see setTextEncoding()
* \see description() * \see description()
*/ */
String::Type textEncoding() const; String::Type textEncoding() const;
/*! /*!
* Set the text encoding used for the description. * Set the text encoding used for the description.
* *
* \see description() * \see description()
*/ */
void setTextEncoding(String::Type t); void setTextEncoding(String::Type t);
/*! /*!
* Returns the mime type of the image. This should in most cases be * Returns the mime type of the image.
* "image/png" or "image/jpeg". * This should in most cases be "image/png" or "image/jpeg".
*/ */
String mimeType() const; String mimeType() const;
/*! /*!
* Sets the mime type of the image. This should in most cases be * Sets the mime type of the image.
* "image/png" or "image/jpeg". * This should in most cases be "image/png" or "image/jpeg".
*/ */
void setMimeType(const String &m); void setMimeType(const String &m);
/*! /*!
* Returns the type of the image. * Returns the type of the image.
* *
* \see Type * \see Type
* \see setType() * \see setType()
*/ */
Type type() const; Type type() const;
/*! /*!
* Sets the type for the image. * Sets the type for the image.
* *
* \see Type * \see Type
* \see type() * \see type()
*/ */
void setType(Type t); void setType(Type t);
/*! /*!
* Returns a text description of the image. * Returns a text description of the image.
* *
* \see setDescription() * \see setDescription()
* \see textEncoding() * \see textEncoding()
* \see setTextEncoding() * \see setTextEncoding()
*/ */
String description() const; String description() const;
/*! /*!
* Sets a textual description of the image to \a desc. * Sets a textual description of the image to \a desc.
* *
* \see description() * \see description()
* \see textEncoding() * \see textEncoding()
* \see setTextEncoding() * \see setTextEncoding()
*/ */
void setDescription(const String &desc); void setDescription(const String &desc);
/*! /*!
* Returns the image data as a ByteVector. * Returns the image data as a ByteVector.
* *
* \note ByteVector has a data() method that returns a const char * which * \note ByteVector has a data() method that returns a const char * which should make it easy to export this data to external programs.
* should make it easy to export this data to external programs. *
* * \see setPicture()
* \see setPicture() * \see mimeType()
* \see mimeType() */
*/
ByteVector picture() const; ByteVector picture() const;
/*! /*!
* Sets the image data to \a p. \a p should be of the type specified in * Sets the image data to \a p. \a p should be of the type specified in this frame's mime-type specification.
* this frame's mime-type specification. *
* * \see picture()
* \see picture() * \see mimeType()
* \see mimeType() * \see setMimeType()
* \see setMimeType() */
*/
void setPicture(const ByteVector &p); void setPicture(const ByteVector &p);
protected: protected:
@@ -222,6 +218,7 @@ class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame {
AttachedPictureFrameV22(const ByteVector &data, Header *h); AttachedPictureFrameV22(const ByteVector &data, Header *h);
friend class FrameFactory; friend class FrameFactory;
}; };
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -35,7 +35,7 @@ using namespace ID3v2;
class ChapterFrame::ChapterFramePrivate { class ChapterFrame::ChapterFramePrivate {
public: public:
ChapterFramePrivate() : tagHeader(0), ChapterFramePrivate() : tagHeader(nullptr),
startTime(0), startTime(0),
endTime(0), endTime(0),
startOffset(0), startOffset(0),
@@ -57,19 +57,14 @@ class ChapterFrame::ChapterFramePrivate {
// public methods // public methods
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : ID3v2::Frame(data), ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : ID3v2::Frame(data), d(new ChapterFramePrivate()) {
d(new ChapterFramePrivate()) {
d->tagHeader = tagHeader; d->tagHeader = tagHeader;
setData(data); setData(data);
} }
ChapterFrame::ChapterFrame(const ByteVector &elementID, ChapterFrame::ChapterFrame(const ByteVector &elementID, unsigned int startTime, unsigned int endTime, unsigned int startOffset, unsigned int endOffset, const FrameList &embeddedFrames) : ID3v2::Frame("CHAP"), d(new ChapterFramePrivate()) {
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset, // setElementID has a workaround for a previously silly API where you had to specifically include the null byte.
const FrameList &embeddedFrames) : ID3v2::Frame("CHAP"),
d(new ChapterFramePrivate()) {
// setElementID has a workaround for a previously silly API where you had to
// specifically include the null byte.
setElementID(elementID); setElementID(elementID);
@@ -82,6 +77,7 @@ ChapterFrame::ChapterFrame(const ByteVector &elementID,
it != embeddedFrames.end(); it != embeddedFrames.end();
++it) ++it)
addEmbeddedFrame(*it); addEmbeddedFrame(*it);
} }
ChapterFrame::~ChapterFrame() { ChapterFrame::~ChapterFrame() {
@@ -109,10 +105,12 @@ unsigned int ChapterFrame::endOffset() const {
} }
void ChapterFrame::setElementID(const ByteVector &eID) { void ChapterFrame::setElementID(const ByteVector &eID) {
d->elementID = eID; d->elementID = eID;
if (d->elementID.endsWith(char(0))) if (d->elementID.endsWith(char(0)))
d->elementID = d->elementID.mid(0, d->elementID.size() - 1); d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
} }
void ChapterFrame::setStartTime(const unsigned int &sT) { void ChapterFrame::setStartTime(const unsigned int &sT) {
@@ -149,6 +147,7 @@ void ChapterFrame::addEmbeddedFrame(Frame *frame) {
} }
void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del) { void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del) {
// remove the frame from the frame list // remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame); FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it); d->embeddedFrameList.erase(it);
@@ -160,15 +159,19 @@ void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del) {
// ...and delete as desired // ...and delete as desired
if (del) if (del)
delete frame; delete frame;
} }
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id) { void ChapterFrame::removeEmbeddedFrames(const ByteVector &id) {
FrameList l = d->embeddedFrameListMap[id]; FrameList l = d->embeddedFrameListMap[id];
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeEmbeddedFrame(*it, true); removeEmbeddedFrame(*it, true);
} }
String ChapterFrame::toString() const { String ChapterFrame::toString() const {
String s = String(d->elementID) + String s = String(d->elementID) +
": start time: " + String::number(d->startTime) + ": start time: " + String::number(d->startTime) +
", end time: " + String::number(d->endTime); ", end time: " + String::number(d->endTime);
@@ -189,18 +192,21 @@ String ChapterFrame::toString() const {
} }
return s; return s;
} }
PropertyMap ChapterFrame::asProperties() const { PropertyMap ChapterFrame::asProperties() const {
PropertyMap map; PropertyMap map;
map.unsupportedData().append(frameID() + String("/") + d->elementID); map.unsupportedData().append(frameID() + String("/") + d->elementID);
return map; return map;
} }
ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) { // static
{
ID3v2::FrameList comments = tag->frameList("CHAP"); ID3v2::FrameList comments = tag->frameList("CHAP");
for (ID3v2::FrameList::ConstIterator it = comments.begin(); for (ID3v2::FrameList::ConstIterator it = comments.begin();
@@ -212,9 +218,11 @@ ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVec
} }
return nullptr; return nullptr;
} }
void ChapterFrame::parseFields(const ByteVector &data) { void ChapterFrame::parseFields(const ByteVector &data) {
unsigned int size = data.size(); unsigned int size = data.size();
if (size < 18) { if (size < 18) {
debug("A CHAP frame must contain at least 18 bytes (1 byte element ID " debug("A CHAP frame must contain at least 18 bytes (1 byte element ID "
@@ -255,9 +263,11 @@ void ChapterFrame::parseFields(const ByteVector &data) {
embPos += frame->size() + header()->size(); embPos += frame->size() + header()->size();
addEmbeddedFrame(frame); addEmbeddedFrame(frame);
} }
} }
ByteVector ChapterFrame::renderFields() const { ByteVector ChapterFrame::renderFields() const {
ByteVector data; ByteVector data;
data.append(d->elementID); data.append(d->elementID);
@@ -271,10 +281,12 @@ ByteVector ChapterFrame::renderFields() const {
data.append((*it)->render()); data.append((*it)->render());
return data; return data;
} }
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h), ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h), d(new ChapterFramePrivate()) {
d(new ChapterFramePrivate()) {
d->tagHeader = tagHeader; d->tagHeader = tagHeader;
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -32,13 +32,12 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
/*! /*!
* This is an implementation of ID3v2 chapter frames. The purpose of this * This is an implementation of ID3v2 chapter frames.
* frame is to describe a single chapter within an audio file. * The purpose of this frame is to describe a single chapter within an audio file.
*/ */
//! An implementation of ID3v2 chapter frames //! An implementation of ID3v2 chapter frames
@@ -47,175 +46,162 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
public: public:
/*! /*!
* Creates a chapter frame based on \a data. \a tagHeader is required as * Creates a chapter frame based on \a data.
* the internal frames are parsed based on the tag version. * \a tagHeader is required as the internal frames are parsed based on the tag version.
*/ */
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data); ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*! /*!
* Creates a chapter frame with the element ID \a elementID, start time * Creates a chapter frame with the element ID \a elementID,
* \a startTime, end time \a endTime, start offset \a startOffset, * start time \a startTime, end time \a endTime, start offset \a startOffset,
* end offset \a endOffset and optionally a list of embedded frames, * end offset \a endOffset and optionally a list of embedded frames,
* whose ownership will then be taken over by this Frame, in * whose ownership will then be taken over by this Frame, in \a embeededFrames;
* \a embeededFrames; *
* * All times are in milliseconds.
* All times are in milliseconds. */
*/
ChapterFrame(const ByteVector &elementID, ChapterFrame(const ByteVector &elementID,
unsigned int startTime, unsigned int endTime, unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset, unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames = FrameList()); const FrameList &embeddedFrames = FrameList());
/*! /*!
* Destroys the frame. * Destroys the frame.
*/ */
virtual ~ChapterFrame(); virtual ~ChapterFrame();
/*! /*!
* Returns the element ID of the frame. Element ID * Returns the element ID of the frame.
* is a null terminated string, however it's not human-readable. * Element ID is a null terminated string, however it's not human-readable.
* *
* \see setElementID() * \see setElementID()
*/ */
ByteVector elementID() const; ByteVector elementID() const;
/*! /*!
* Returns time of chapter's start (in milliseconds). * Returns time of chapter's start (in milliseconds).
* *
* \see setStartTime() * \see setStartTime()
*/ */
unsigned int startTime() const; unsigned int startTime() const;
/*! /*!
* Returns time of chapter's end (in milliseconds). * Returns time of chapter's end (in milliseconds).
* *
* \see setEndTime() * \see setEndTime()
*/ */
unsigned int endTime() const; unsigned int endTime() const;
/*! /*!
* Returns zero based byte offset (count of bytes from the beginning * Returns zero based byte offset (count of bytes from the beginning of the audio file) of chapter's start.
* of the audio file) of chapter's start. *
* * \note If returned value is 0xFFFFFFFF, start time should be used instead.
* \note If returned value is 0xFFFFFFFF, start time should be used instead. * \see setStartOffset()
* \see setStartOffset() */
*/
unsigned int startOffset() const; unsigned int startOffset() const;
/*! /*!
* Returns zero based byte offset (count of bytes from the beginning * Returns zero based byte offset (count of bytes from the beginning of the audio file) of chapter's end.
* of the audio file) of chapter's end. *
* * \note If returned value is 0xFFFFFFFF, end time should be used instead.
* \note If returned value is 0xFFFFFFFF, end time should be used instead. * \see setEndOffset()
* \see setEndOffset() */
*/
unsigned int endOffset() const; unsigned int endOffset() const;
/*! /*!
* Sets the element ID of the frame to \a eID. If \a eID isn't * Sets the element ID of the frame to \a eID. If \a eID isn't null terminated, a null char is appended automatically.
* null terminated, a null char is appended automatically. *
* * \see elementID()
* \see elementID() */
*/
void setElementID(const ByteVector &eID); void setElementID(const ByteVector &eID);
/*! /*!
* Sets time of chapter's start (in milliseconds) to \a sT. * Sets time of chapter's start (in milliseconds) to \a sT.
* *
* \see startTime() * \see startTime()
*/ */
void setStartTime(const unsigned int &sT); void setStartTime(const unsigned int &sT);
/*! /*!
* Sets time of chapter's end (in milliseconds) to \a eT. * Sets time of chapter's end (in milliseconds) to \a eT.
* *
* \see endTime() * \see endTime()
*/ */
void setEndTime(const unsigned int &eT); void setEndTime(const unsigned int &eT);
/*! /*!
* Sets zero based byte offset (count of bytes from the beginning * Sets zero based byte offset (count of bytes from the beginning of the audio file) of chapter's start to \a sO.
* of the audio file) of chapter's start to \a sO. *
* * \see startOffset()
* \see startOffset() */
*/
void setStartOffset(const unsigned int &sO); void setStartOffset(const unsigned int &sO);
/*! /*!
* Sets zero based byte offset (count of bytes from the beginning * Sets zero based byte offset (count of bytes from the beginning of the audio file) of chapter's end to \a eO.
* of the audio file) of chapter's end to \a eO. *
* * \see endOffset()
* \see endOffset() */
*/
void setEndOffset(const unsigned int &eO); void setEndOffset(const unsigned int &eO);
/*! /*!
* Returns a reference to the frame list map. This is an FrameListMap of * Returns a reference to the frame list map.
* all of the frames embedded in the CHAP frame. * This is an FrameListMap of all of the frames embedded in the CHAP frame.
* *
* This is the most convenient structure for accessing the CHAP frame's * This is the most convenient structure for accessing the CHAP frame's embedded frames.
* embedded frames. Many frame types allow multiple instances of the same * Many frame types allow multiple instances of the same rame type so this is a map of lists.
* frame type so this is a map of lists. In most cases however there will * In most cases however there will only be a single frame of a certain type.
* only be a single frame of a certain type. *
* * \warning You should not modify this data structure directly, instead
* \warning You should not modify this data structure directly, instead * use addEmbeddedFrame() and removeEmbeddedFrame().
* use addEmbeddedFrame() and removeEmbeddedFrame(). *
* * \see embeddedFrameList()
* \see embeddedFrameList() */
*/
const FrameListMap &embeddedFrameListMap() const; const FrameListMap &embeddedFrameListMap() const;
/*! /*!
* Returns a reference to the embedded frame list. This is an FrameList * Returns a reference to the embedded frame list.
* of all of the frames embedded in the CHAP frame in the order that they * This is an FrameList of all of the frames embedded in the CHAP frame in the order that they were parsed.
* were parsed. *
* * This can be useful if for example you want iterate over the CHAP frame's
* This can be useful if for example you want iterate over the CHAP frame's * embedded frames in the order that they occur in the CHAP frame.
* embedded frames in the order that they occur in the CHAP frame. *
* * \warning You should not modify this data structure directly,
* \warning You should not modify this data structure directly, instead * instead use addEmbeddedFrame() and removeEmbeddedFrame().
* use addEmbeddedFrame() and removeEmbeddedFrame(). */
*/
const FrameList &embeddedFrameList() const; const FrameList &embeddedFrameList() const;
/*! /*!
* Returns the embedded frame list for frames with the id \a frameID * Returns the embedded frame list for frames with the id \a frameID or an empty list if there are no embedded frames of that type.
* or an empty list if there are no embedded frames of that type. This * This is just a convenience and is equivalent to:
* is just a convenience and is equivalent to: *
* * \code
* \code * embeddedFrameListMap()[frameID];
* embeddedFrameListMap()[frameID]; * \endcode
* \endcode *
* * \see embeddedFrameListMap()
* \see embeddedFrameListMap() */
*/
const FrameList &embeddedFrameList(const ByteVector &frameID) const; const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*! /*!
* Add an embedded frame to the CHAP frame. At this point the CHAP frame * Add an embedded frame to the CHAP frame.
* takes ownership of the embedded frame and will handle freeing its memory. * At this point the CHAP frame takes ownership of the embedded frame and will handle freeing its memory.
* *
* \note Using this method will invalidate any pointers on the list * \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
* returned by embeddedFrameList() */
*/
void addEmbeddedFrame(Frame *frame); void addEmbeddedFrame(Frame *frame);
/*! /*!
* Remove an embedded frame from the CHAP frame. If \a del is true the frame's * Remove an embedded frame from the CHAP frame.
* memory will be freed; if it is false, it must be deleted by the user. * If \a del is true the frame's memory will be freed; if it is false, it must be deleted by the user.
* *
* \note Using this method will invalidate any pointers on the list * \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
* returned by embeddedFrameList() */
*/
void removeEmbeddedFrame(Frame *frame, bool del = true); void removeEmbeddedFrame(Frame *frame, bool del = true);
/*! /*!
* Remove all embedded frames of type \a id from the CHAP frame and free their * Remove all embedded frames of type \a id from the CHAP frame and free their memory.
* memory. *
* * \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
* \note Using this method will invalidate any pointers on the list */
* returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id); void removeEmbeddedFrames(const ByteVector &id);
virtual String toString() const; virtual String toString() const;
@@ -223,12 +209,11 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
PropertyMap asProperties() const; PropertyMap asProperties() const;
/*! /*!
* CHAP frames each have a unique element ID. This searches for a CHAP * CHAP frames each have a unique element ID. This searches for a CHAP frame with the element ID \a eID and returns a pointer to it.
* frame with the element ID \a eID and returns a pointer to it. This * This can be used to link CTOC and CHAP frames together.
* can be used to link CTOC and CHAP frames together. *
* * \see elementID()
* \see elementID() */
*/
static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID); static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID);
protected: protected:
@@ -243,6 +228,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
class ChapterFramePrivate; class ChapterFramePrivate;
ChapterFramePrivate *d; ChapterFramePrivate *d;
}; };
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -47,13 +47,11 @@ class CommentsFrame::CommentsFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM"), CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM"), d(new CommentsFramePrivate()) {
d(new CommentsFramePrivate()) {
d->textEncoding = encoding; d->textEncoding = encoding;
} }
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data), CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data), d(new CommentsFramePrivate()) {
d(new CommentsFramePrivate()) {
setData(data); setData(data);
} }
@@ -98,6 +96,7 @@ void CommentsFrame::setTextEncoding(String::Type encoding) {
} }
PropertyMap CommentsFrame::asProperties() const { PropertyMap CommentsFrame::asProperties() const {
String key = description().upper(); String key = description().upper();
PropertyMap map; PropertyMap map;
if (key.isEmpty() || key == "COMMENT") if (key.isEmpty() || key == "COMMENT")
@@ -105,10 +104,11 @@ PropertyMap CommentsFrame::asProperties() const {
else else
map.insert("COMMENT:" + key, text()); map.insert("COMMENT:" + key, text());
return map; return map;
} }
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) { // static
{
ID3v2::FrameList comments = tag->frameList("COMM"); ID3v2::FrameList comments = tag->frameList("COMM");
for (ID3v2::FrameList::ConstIterator it = comments.begin(); for (ID3v2::FrameList::ConstIterator it = comments.begin();
@@ -120,6 +120,7 @@ CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const Str
} }
return nullptr; return nullptr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -127,6 +128,7 @@ CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const Str
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CommentsFrame::parseFields(const ByteVector &data) { void CommentsFrame::parseFields(const ByteVector &data) {
if (data.size() < 5) { if (data.size() < 5) {
debug("A comment frame must contain at least 5 bytes."); debug("A comment frame must contain at least 5 bytes.");
return; return;
@@ -149,9 +151,11 @@ void CommentsFrame::parseFields(const ByteVector &data) {
d->text = String(l.back(), d->textEncoding); d->text = String(l.back(), d->textEncoding);
} }
} }
} }
ByteVector CommentsFrame::renderFields() const { ByteVector CommentsFrame::renderFields() const {
ByteVector v; ByteVector v;
String::Type encoding = d->textEncoding; String::Type encoding = d->textEncoding;
@@ -166,13 +170,13 @@ ByteVector CommentsFrame::renderFields() const {
v.append(d->text.data(encoding)); v.append(d->text.data(encoding));
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h), CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h), d(new CommentsFramePrivate()) {
d(new CommentsFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -31,129 +31,124 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An implementation of ID3v2 comments //! An implementation of ID3v2 comments
/*! /*!
* This implements the ID3v2 comment format. An ID3v2 comment consists of * This implements the ID3v2 comment format. An ID3v2 comment consists of
* a language encoding, a description and a single text field. * a language encoding, a description and a single text field.
*/ */
class TAGLIB_EXPORT CommentsFrame : public Frame { class TAGLIB_EXPORT CommentsFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Construct an empty comment frame that will use the text encoding * Construct an empty comment frame that will use the text encoding \a encoding.
* \a encoding. */
*/
explicit CommentsFrame(String::Type encoding = String::Latin1); explicit CommentsFrame(String::Type encoding = String::Latin1);
/*! /*!
* Construct a comment based on the data in \a data. * Construct a comment based on the data in \a data.
*/ */
explicit CommentsFrame(const ByteVector &data); explicit CommentsFrame(const ByteVector &data);
/*! /*!
* Destroys this CommentFrame instance. * Destroys this CommentFrame instance.
*/ */
virtual ~CommentsFrame(); virtual ~CommentsFrame();
/*! /*!
* Returns the text of this comment. * Returns the text of this comment.
* *
* \see text() * \see text()
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the language encoding as a 3 byte encoding as specified by * Returns the language encoding as a 3 byte encoding as specified by
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>. * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
* *
* \note Most taggers simply ignore this value. * \note Most taggers simply ignore this value.
* *
* \see setLanguage() * \see setLanguage()
*/ */
ByteVector language() const; ByteVector language() const;
/*! /*!
* Returns the description of this comment. * Returns the description of this comment.
* *
* \note Most taggers simply ignore this value. * \note Most taggers simply ignore this value.
* *
* \see setDescription() * \see setDescription()
*/ */
String description() const; String description() const;
/*! /*!
* Returns the text of this comment. * Returns the text of this comment.
* *
* \see setText() * \see setText()
*/ */
String text() const; String text() const;
/*! /*!
* Set the language using the 3 byte language code from * Set the language using the 3 byte language code from
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to \a languageCode.
* \a languageCode. *
* * \see language()
* \see language() */
*/
void setLanguage(const ByteVector &languageCode); void setLanguage(const ByteVector &languageCode);
/*! /*!
* Sets the description of the comment to \a s. * Sets the description of the comment to \a s.
* *
* \see description() * \see description()
*/ */
void setDescription(const String &s); void setDescription(const String &s);
/*! /*!
* Sets the text portion of the comment to \a s. * Sets the text portion of the comment to \a s.
* *
* \see text() * \see text()
*/ */
virtual void setText(const String &s); virtual void setText(const String &s);
/*! /*!
* Returns the text encoding that will be used in rendering this frame. * Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor * This defaults to the type that was either specified in the constructor or read from the frame when parsed.
* or read from the frame when parsed. *
* * \see setTextEncoding()
* \see setTextEncoding() * \see render()
* \see render() */
*/
String::Type textEncoding() const; String::Type textEncoding() const;
/*! /*!
* Sets the text encoding to be used when rendering this frame to * Sets the text encoding to be used when rendering this frame to \a encoding.
* \a encoding. *
* * \see textEncoding()
* \see textEncoding() * \see render()
* \see render() */
*/
void setTextEncoding(String::Type encoding); void setTextEncoding(String::Type encoding);
/*! /*!
* Parses this frame as PropertyMap with a single key. * Parses this frame as PropertyMap with a single key.
* - if description() is empty or "COMMENT", the key will be "COMMENT" * - if description() is empty or "COMMENT", the key will be "COMMENT"
* - if description() is not a valid PropertyMap key, the frame will be * - if description() is not a valid PropertyMap key, the frame will be
* marked unsupported by an entry "COMM/<description>" in the unsupportedData() * marked unsupported by an entry "COMM/<description>" in the unsupportedData()
* attribute of the returned map. * attribute of the returned map.
* - otherwise, the key will be "COMMENT:<description>" * - otherwise, the key will be "COMMENT:<description>"
* - The single value will be the frame's text(). * - The single value will be the frame's text().
*/ */
PropertyMap asProperties() const; PropertyMap asProperties() const;
/*! /*!
* Comments each have a unique description. This searches for a comment * Comments each have a unique description.
* frame with the description \a d and returns a pointer to it. If no * This searches for a comment frame with the description \a d and returns a pointer to it.
* frame is found that matches the given description null is returned. * If no frame is found that matches the given description null is returned.
* *
* \see description() * \see description()
*/ */
static CommentsFrame *findByDescription(const Tag *tag, const String &d); static CommentsFrame *findByDescription(const Tag *tag, const String &d);
protected: protected:
@@ -164,8 +159,8 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
CommentsFrame(const ByteVector &data, Header *h); CommentsFrame(const ByteVector &data, Header *h);
CommentsFrame(const CommentsFrame &); CommentsFrame(const CommentsFrame &);
CommentsFrame &operator=(const CommentsFrame &); CommentsFrame &operator=(const CommentsFrame &);
@@ -177,4 +172,5 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -43,12 +43,9 @@ class EventTimingCodesFrame::EventTimingCodesFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame() : Frame("ETCO"), EventTimingCodesFrame::EventTimingCodesFrame() : Frame("ETCO"), d(new EventTimingCodesFramePrivate()) {}
d(new EventTimingCodesFramePrivate()) {
}
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) : Frame(data), EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) : Frame(data), d(new EventTimingCodesFramePrivate()) {
d(new EventTimingCodesFramePrivate()) {
setData(data); setData(data);
} }
@@ -85,6 +82,7 @@ void EventTimingCodesFrame::setSynchedEvents(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void EventTimingCodesFrame::parseFields(const ByteVector &data) { void EventTimingCodesFrame::parseFields(const ByteVector &data) {
const int end = data.size(); const int end = data.size();
if (end < 1) { if (end < 1) {
debug("An event timing codes frame must contain at least 1 byte."); debug("An event timing codes frame must contain at least 1 byte.");
@@ -101,28 +99,28 @@ void EventTimingCodesFrame::parseFields(const ByteVector &data) {
pos += 4; pos += 4;
d->synchedEvents.append(SynchedEvent(time, type)); d->synchedEvents.append(SynchedEvent(time, type));
} }
} }
ByteVector EventTimingCodesFrame::renderFields() const { ByteVector EventTimingCodesFrame::renderFields() const {
ByteVector v; ByteVector v;
v.append(char(d->timestampFormat)); v.append(char(d->timestampFormat));
for (SynchedEventList::ConstIterator it = d->synchedEvents.begin(); for (SynchedEventList::ConstIterator it = d->synchedEvents.begin(); it != d->synchedEvents.end(); ++it) {
it != d->synchedEvents.end();
++it) {
const SynchedEvent &entry = *it; const SynchedEvent &entry = *it;
v.append(char(entry.type)); v.append(char(entry.type));
v.append(ByteVector::fromUInt(entry.time)); v.append(ByteVector::fromUInt(entry.time));
} }
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) : Frame(h), EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) : Frame(h), d(new EventTimingCodesFramePrivate()) {
d(new EventTimingCodesFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -31,20 +31,19 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! ID3v2 event timing codes frame //! ID3v2 event timing codes frame
/*! /*!
* An implementation of ID3v2 event timing codes. * An implementation of ID3v2 event timing codes.
*/ */
class TAGLIB_EXPORT EventTimingCodesFrame : public Frame { class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Specifies the timestamp format used. * Specifies the timestamp format used.
*/ */
enum TimestampFormat { enum TimestampFormat {
//! The timestamp is of unknown format. //! The timestamp is of unknown format.
Unknown = 0x00, Unknown = 0x00,
@@ -57,8 +56,8 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
}; };
/*! /*!
* Event types defined in id3v2.4.0-frames.txt 4.5. Event timing codes. * Event types defined in id3v2.4.0-frames.txt 4.5. Event timing codes.
*/ */
enum EventType { enum EventType {
Padding = 0x00, Padding = 0x00,
EndOfInitialSilence = 0x01, EndOfInitialSilence = 0x01,
@@ -104,8 +103,8 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
}; };
/*! /*!
* Single entry of time stamp and event. * Single entry of time stamp and event.
*/ */
struct SynchedEvent { struct SynchedEvent {
SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {} SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {}
unsigned int time; unsigned int time;
@@ -113,52 +112,52 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
}; };
/*! /*!
* List of synchronized events. * List of synchronized events.
*/ */
typedef Strawberry_TagLib::TagLib::List<SynchedEvent> SynchedEventList; typedef Strawberry_TagLib::TagLib::List<SynchedEvent> SynchedEventList;
/*! /*!
* Construct an empty event timing codes frame. * Construct an empty event timing codes frame.
*/ */
explicit EventTimingCodesFrame(); explicit EventTimingCodesFrame();
/*! /*!
* Construct a event timing codes frame based on the data in \a data. * Construct a event timing codes frame based on the data in \a data.
*/ */
explicit EventTimingCodesFrame(const ByteVector &data); explicit EventTimingCodesFrame(const ByteVector &data);
/*! /*!
* Destroys this EventTimingCodesFrame instance. * Destroys this EventTimingCodesFrame instance.
*/ */
virtual ~EventTimingCodesFrame(); virtual ~EventTimingCodesFrame();
/*! /*!
* Returns a null string. * Returns a null string.
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the timestamp format. * Returns the timestamp format.
*/ */
TimestampFormat timestampFormat() const; TimestampFormat timestampFormat() const;
/*! /*!
* Returns the events with the time stamps. * Returns the events with the time stamps.
*/ */
SynchedEventList synchedEvents() const; SynchedEventList synchedEvents() const;
/*! /*!
* Set the timestamp format. * Set the timestamp format.
* *
* \see timestampFormat() * \see timestampFormat()
*/ */
void setTimestampFormat(TimestampFormat f); void setTimestampFormat(TimestampFormat f);
/*! /*!
* Sets the text with the time stamps. * Sets the text with the time stamps.
* *
* \see text() * \see text()
*/ */
void setSynchedEvents(const SynchedEventList &e); void setSynchedEvents(const SynchedEventList &e);
protected: protected:
@@ -169,8 +168,8 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
EventTimingCodesFrame(const ByteVector &data, Header *h); EventTimingCodesFrame(const ByteVector &data, Header *h);
EventTimingCodesFrame(const EventTimingCodesFrame &); EventTimingCodesFrame(const EventTimingCodesFrame &);
EventTimingCodesFrame &operator=(const EventTimingCodesFrame &); EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
@@ -182,4 +181,5 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -49,12 +49,9 @@ class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB"), GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB"), d(new GeneralEncapsulatedObjectFramePrivate()) {}
d(new GeneralEncapsulatedObjectFramePrivate()) {
}
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data), GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data), d(new GeneralEncapsulatedObjectFramePrivate()) {
d(new GeneralEncapsulatedObjectFramePrivate()) {
setData(data); setData(data);
} }
@@ -63,6 +60,7 @@ GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame() {
} }
String GeneralEncapsulatedObjectFrame::toString() const { String GeneralEncapsulatedObjectFrame::toString() const {
String text = "[" + d->mimeType + "]"; String text = "[" + d->mimeType + "]";
if (!d->fileName.isEmpty()) if (!d->fileName.isEmpty())
@@ -72,6 +70,7 @@ String GeneralEncapsulatedObjectFrame::toString() const {
text += " \"" + d->description + "\""; text += " \"" + d->description + "\"";
return text; return text;
} }
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const { String::Type GeneralEncapsulatedObjectFrame::textEncoding() const {
@@ -119,6 +118,7 @@ void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) { void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) {
if (data.size() < 4) { if (data.size() < 4) {
debug("An object frame must contain at least 4 bytes."); debug("An object frame must contain at least 4 bytes.");
return; return;
@@ -133,9 +133,11 @@ void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) {
d->description = readStringField(data, d->textEncoding, &pos); d->description = readStringField(data, d->textEncoding, &pos);
d->data = data.mid(pos); d->data = data.mid(pos);
} }
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const { ByteVector GeneralEncapsulatedObjectFrame::renderFields() const {
StringList sl; StringList sl;
sl.append(d->fileName); sl.append(d->fileName);
sl.append(d->description); sl.append(d->description);
@@ -154,13 +156,13 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const {
data.append(d->data); data.append(d->data);
return data; return data;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h), GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h), d(new GeneralEncapsulatedObjectFramePrivate()) {
d(new GeneralEncapsulatedObjectFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -35,129 +35,128 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An ID3v2 general encapsulated object frame implementation //! An ID3v2 general encapsulated object frame implementation
/*! /*!
* This is an implementation of ID3v2 general encapsulated objects. * This is an implementation of ID3v2 general encapsulated objects.
* Arbitrary binary data may be included in tags, stored in GEOB frames. * Arbitrary binary data may be included in tags, stored in GEOB frames.
* There may be multiple GEOB frames in a single tag. Each GEOB it * There may be multiple GEOB frames in a single tag.
* labelled with a content description (which may be blank), a required * Each GEOB it labelled with a content description (which may be blank),
* mime-type, and a file name (may be blank). The content description * a required mime-type, and a file name (may be blank).
* uniquely identifies the GEOB frame in the tag. * The content description uniquely identifies the GEOB frame in the tag.
*/ */
class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame { class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Constructs an empty object frame. The description, file name and text * Constructs an empty object frame.
* encoding should be set manually. * The description, file name and text encoding should be set manually.
*/ */
GeneralEncapsulatedObjectFrame(); GeneralEncapsulatedObjectFrame();
/*! /*!
* Constructs a GeneralEncapsulatedObjectFrame frame based on \a data. * Constructs a GeneralEncapsulatedObjectFrame frame based on \a data.
* *
* \warning This is \em not data for the encapsulated object, for that use * \warning This is \em not data for the encapsulated object, for that use
* setObject(). This constructor is used when reading the frame from the * setObject().
* disk. * This constructor is used when reading the frame from the disk.
*/ */
explicit GeneralEncapsulatedObjectFrame(const ByteVector &data); explicit GeneralEncapsulatedObjectFrame(const ByteVector &data);
/*! /*!
* Destroys the GeneralEncapsulatedObjectFrame instance. * Destroys the GeneralEncapsulatedObjectFrame instance.
*/ */
virtual ~GeneralEncapsulatedObjectFrame(); virtual ~GeneralEncapsulatedObjectFrame();
/*! /*!
* Returns a string containing the description, file name and mime-type * Returns a string containing the description, file name and mime-type
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the text encoding used for the description and file name. * Returns the text encoding used for the description and file name.
* *
* \see setTextEncoding() * \see setTextEncoding()
* \see description() * \see description()
* \see fileName() * \see fileName()
*/ */
String::Type textEncoding() const; String::Type textEncoding() const;
/*! /*!
* Set the text encoding used for the description and file name. * Set the text encoding used for the description and file name.
* *
* \see description() * \see description()
* \see fileName() * \see fileName()
*/ */
void setTextEncoding(String::Type encoding); void setTextEncoding(String::Type encoding);
/*! /*!
* Returns the mime type of the object. * Returns the mime type of the object.
*/ */
String mimeType() const; String mimeType() const;
/*! /*!
* Sets the mime type of the object. * Sets the mime type of the object.
*/ */
void setMimeType(const String &type); void setMimeType(const String &type);
/*! /*!
* Returns the file name of the object. * Returns the file name of the object.
* *
* \see setFileName() * \see setFileName()
*/ */
String fileName() const; String fileName() const;
/*! /*!
* Sets the file name for the object. * Sets the file name for the object.
* *
* \see fileName() * \see fileName()
*/ */
void setFileName(const String &name); void setFileName(const String &name);
/*! /*!
* Returns the content description of the object. * Returns the content description of the object.
* *
* \see setDescription() * \see setDescription()
* \see textEncoding() * \see textEncoding()
* \see setTextEncoding() * \see setTextEncoding()
*/ */
String description() const; String description() const;
/*! /*!
* Sets the content description of the object to \a desc. * Sets the content description of the object to \a desc.
* *
* \see description() * \see description()
* \see textEncoding() * \see textEncoding()
* \see setTextEncoding() * \see setTextEncoding()
*/ */
void setDescription(const String &desc); void setDescription(const String &desc);
/*! /*!
* Returns the object data as a ByteVector. * Returns the object data as a ByteVector.
* *
* \note ByteVector has a data() method that returns a const char * which * \note ByteVector has a data() method that returns a const char * which
* should make it easy to export this data to external programs. * should make it easy to export this data to external programs.
* *
* \see setObject() * \see setObject()
* \see mimeType() * \see mimeType()
*/ */
ByteVector object() const; ByteVector object() const;
/*! /*!
* Sets the object data to \a data. \a data should be of the type specified in * Sets the object data to \a data.
* this frame's mime-type specification. * \a data should be of the type specified in this frame's mime-type specification.
* *
* \see object() * \see object()
* \see mimeType() * \see mimeType()
* \see setMimeType() * \see setMimeType()
*/ */
void setObject(const ByteVector &object); void setObject(const ByteVector &object);
protected: protected:
@@ -172,6 +171,7 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
class GeneralEncapsulatedObjectFramePrivate; class GeneralEncapsulatedObjectFramePrivate;
GeneralEncapsulatedObjectFramePrivate *d; GeneralEncapsulatedObjectFramePrivate *d;
}; };
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -44,13 +44,11 @@ class OwnershipFrame::OwnershipFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE"), OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE"),d(new OwnershipFramePrivate()) {
d(new OwnershipFramePrivate()) {
d->textEncoding = encoding; d->textEncoding = encoding;
} }
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data), OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data),d(new OwnershipFramePrivate()) {
d(new OwnershipFramePrivate()) {
setData(data); setData(data);
} }
@@ -99,6 +97,7 @@ void OwnershipFrame::setTextEncoding(String::Type encoding) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void OwnershipFrame::parseFields(const ByteVector &data) { void OwnershipFrame::parseFields(const ByteVector &data) {
int pos = 0; int pos = 0;
// Get the text encoding // Get the text encoding
@@ -123,9 +122,11 @@ void OwnershipFrame::parseFields(const ByteVector &data) {
d->seller = Tag::latin1StringHandler()->parse(data.mid(pos)); d->seller = Tag::latin1StringHandler()->parse(data.mid(pos));
else else
d->seller = String(data.mid(pos), d->textEncoding); d->seller = String(data.mid(pos), d->textEncoding);
} }
ByteVector OwnershipFrame::renderFields() const { ByteVector OwnershipFrame::renderFields() const {
StringList sl; StringList sl;
sl.append(d->seller); sl.append(d->seller);
@@ -140,13 +141,13 @@ ByteVector OwnershipFrame::renderFields() const {
v.append(d->seller.data(encoding)); v.append(d->seller.data(encoding));
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h), OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h), d(new OwnershipFramePrivate()) {
d(new OwnershipFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -31,101 +31,98 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An implementation of ID3v2 "ownership" //! An implementation of ID3v2 "ownership"
/*! /*!
* This implements the ID3v2 ownership (OWNE frame). It consists of * This implements the ID3v2 ownership (OWNE frame).
* a price paid, a date purchased (YYYYMMDD) and the name of the seller. * It consists of a price paid, a date purchased (YYYYMMDD) and the name of the seller.
*/ */
class TAGLIB_EXPORT OwnershipFrame : public Frame { class TAGLIB_EXPORT OwnershipFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Construct an empty ownership frame. * Construct an empty ownership frame.
*/ */
explicit OwnershipFrame(String::Type encoding = String::Latin1); explicit OwnershipFrame(String::Type encoding = String::Latin1);
/*! /*!
* Construct a ownership based on the data in \a data. * Construct a ownership based on the data in \a data.
*/ */
explicit OwnershipFrame(const ByteVector &data); explicit OwnershipFrame(const ByteVector &data);
/*! /*!
* Destroys this OwnershipFrame instance. * Destroys this OwnershipFrame instance.
*/ */
virtual ~OwnershipFrame(); virtual ~OwnershipFrame();
/*! /*!
* Returns the text of this popularimeter. * Returns the text of this popularimeter.
* *
* \see text() * \see text()
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the date purchased. * Returns the date purchased.
* *
* \see setDatePurchased() * \see setDatePurchased()
*/ */
String datePurchased() const; String datePurchased() const;
/*! /*!
* Set the date purchased. * Set the date purchased.
* *
* \see datePurchased() * \see datePurchased()
*/ */
void setDatePurchased(const String &datePurchased); void setDatePurchased(const String &datePurchased);
/*! /*!
* Returns the price paid. * Returns the price paid.
* *
* \see setPricePaid() * \see setPricePaid()
*/ */
String pricePaid() const; String pricePaid() const;
/*! /*!
* Set the price paid. * Set the price paid.
* *
* \see pricePaid() * \see pricePaid()
*/ */
void setPricePaid(const String &pricePaid); void setPricePaid(const String &pricePaid);
/*! /*!
* Returns the seller. * Returns the seller.
* *
* \see setSeller() * \see setSeller()
*/ */
String seller() const; String seller() const;
/*! /*!
* Set the seller. * Set the seller.
* *
* \see seller() * \see seller()
*/ */
void setSeller(const String &seller); void setSeller(const String &seller);
/*! /*!
* Returns the text encoding that will be used in rendering this frame. * Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor * This defaults to the type that was either specified in the constructor or read from the frame when parsed.
* or read from the frame when parsed. *
* * \see setTextEncoding()
* \see setTextEncoding() * \see render()
* \see render() */
*/
String::Type textEncoding() const; String::Type textEncoding() const;
/*! /*!
* Sets the text encoding to be used when rendering this frame to * Sets the text encoding to be used when rendering this frame to \a encoding.
* \a encoding. *
* * \see textEncoding()
* \see textEncoding() * \see render()
* \see render() */
*/
void setTextEncoding(String::Type encoding); void setTextEncoding(String::Type encoding);
protected: protected:
@@ -136,8 +133,8 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
OwnershipFrame(const ByteVector &data, Header *h); OwnershipFrame(const ByteVector &data, Header *h);
OwnershipFrame(const OwnershipFrame &); OwnershipFrame(const OwnershipFrame &);
OwnershipFrame &operator=(const OwnershipFrame &); OwnershipFrame &operator=(const OwnershipFrame &);
@@ -149,4 +146,5 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -37,8 +37,7 @@ class PodcastFrame::PodcastFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame() : Frame("PCST"), PodcastFrame::PodcastFrame() : Frame("PCST"), d(new PodcastFramePrivate()) {
d(new PodcastFramePrivate()) {
d->fieldData = ByteVector(4, '\0'); d->fieldData = ByteVector(4, '\0');
} }
@@ -66,7 +65,6 @@ ByteVector PodcastFrame::renderFields() const {
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h), PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h), d(new PodcastFramePrivate()) {
d(new PodcastFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -31,30 +31,29 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! ID3v2 podcast frame //! ID3v2 podcast frame
/*! /*!
* An implementation of ID3v2 podcast flag, a frame with four zero bytes. * An implementation of ID3v2 podcast flag, a frame with four zero bytes.
*/ */
class TAGLIB_EXPORT PodcastFrame : public Frame { class TAGLIB_EXPORT PodcastFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Construct a podcast frame. * Construct a podcast frame.
*/ */
PodcastFrame(); PodcastFrame();
/*! /*!
* Destroys this PodcastFrame instance. * Destroys this PodcastFrame instance.
*/ */
virtual ~PodcastFrame(); virtual ~PodcastFrame();
/*! /*!
* Returns a null string. * Returns a null string.
*/ */
virtual String toString() const; virtual String toString() const;
protected: protected:
@@ -65,8 +64,8 @@ class TAGLIB_EXPORT PodcastFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
PodcastFrame(const ByteVector &data, Header *h); PodcastFrame(const ByteVector &data, Header *h);
PodcastFrame(const PodcastFrame &); PodcastFrame(const PodcastFrame &);
PodcastFrame &operator=(const PodcastFrame &); PodcastFrame &operator=(const PodcastFrame &);
@@ -78,4 +77,5 @@ class TAGLIB_EXPORT PodcastFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -42,12 +42,9 @@ class PopularimeterFrame::PopularimeterFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame() : Frame("POPM"), PopularimeterFrame::PopularimeterFrame() : Frame("POPM"), d(new PopularimeterFramePrivate()) {}
d(new PopularimeterFramePrivate()) {
}
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data), PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data), d(new PopularimeterFramePrivate()) {
d(new PopularimeterFramePrivate()) {
setData(data); setData(data);
} }
@@ -88,6 +85,7 @@ void PopularimeterFrame::setCounter(unsigned int s) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void PopularimeterFrame::parseFields(const ByteVector &data) { void PopularimeterFrame::parseFields(const ByteVector &data) {
int pos = 0, size = int(data.size()); int pos = 0, size = int(data.size());
d->email = readStringField(data, String::Latin1, &pos); d->email = readStringField(data, String::Latin1, &pos);
@@ -100,9 +98,11 @@ void PopularimeterFrame::parseFields(const ByteVector &data) {
d->counter = data.toUInt(static_cast<unsigned int>(pos)); d->counter = data.toUInt(static_cast<unsigned int>(pos));
} }
} }
} }
ByteVector PopularimeterFrame::renderFields() const { ByteVector PopularimeterFrame::renderFields() const {
ByteVector data; ByteVector data;
data.append(d->email.data(String::Latin1)); data.append(d->email.data(String::Latin1));
@@ -111,13 +111,13 @@ ByteVector PopularimeterFrame::renderFields() const {
data.append(ByteVector::fromUInt(d->counter)); data.append(ByteVector::fromUInt(d->counter));
return data; return data;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h), PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h), d(new PopularimeterFramePrivate()) {
d(new PopularimeterFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -31,82 +31,81 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An implementation of ID3v2 "popularimeter" //! An implementation of ID3v2 "popularimeter"
/*! /*!
* This implements the ID3v2 popularimeter (POPM frame). It consists of * This implements the ID3v2 popularimeter (POPM frame).
* an email, a rating and an optional counter. * It consists of an email, a rating and an optional counter.
*/ */
class TAGLIB_EXPORT PopularimeterFrame : public Frame { class TAGLIB_EXPORT PopularimeterFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Construct an empty popularimeter frame. * Construct an empty popularimeter frame.
*/ */
explicit PopularimeterFrame(); explicit PopularimeterFrame();
/*! /*!
* Construct a popularimeter based on the data in \a data. * Construct a popularimeter based on the data in \a data.
*/ */
explicit PopularimeterFrame(const ByteVector &data); explicit PopularimeterFrame(const ByteVector &data);
/*! /*!
* Destroys this PopularimeterFrame instance. * Destroys this PopularimeterFrame instance.
*/ */
virtual ~PopularimeterFrame(); virtual ~PopularimeterFrame();
/*! /*!
* Returns the text of this popularimeter. * Returns the text of this popularimeter.
* *
* \see text() * \see text()
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the email. * Returns the email.
* *
* \see setEmail() * \see setEmail()
*/ */
String email() const; String email() const;
/*! /*!
* Set the email. * Set the email.
* *
* \see email() * \see email()
*/ */
void setEmail(const String &email); void setEmail(const String &email);
/*! /*!
* Returns the rating. * Returns the rating.
* *
* \see setRating() * \see setRating()
*/ */
int rating() const; int rating() const;
/*! /*!
* Set the rating. * Set the rating.
* *
* \see rating() * \see rating()
*/ */
void setRating(int rating); void setRating(int rating);
/*! /*!
* Returns the counter. * Returns the counter.
* *
* \see setCounter() * \see setCounter()
*/ */
unsigned int counter() const; unsigned int counter() const;
/*! /*!
* Set the counter. * Set the counter.
* *
* \see counter() * \see counter()
*/ */
void setCounter(unsigned int counter); void setCounter(unsigned int counter);
protected: protected:
@@ -117,8 +116,8 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
PopularimeterFrame(const ByteVector &data, Header *h); PopularimeterFrame(const ByteVector &data, Header *h);
PopularimeterFrame(const PopularimeterFrame &); PopularimeterFrame(const PopularimeterFrame &);
PopularimeterFrame &operator=(const PopularimeterFrame &); PopularimeterFrame &operator=(const PopularimeterFrame &);
@@ -130,4 +129,5 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -44,12 +44,9 @@ class PrivateFrame::PrivateFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame() : Frame("PRIV"), PrivateFrame::PrivateFrame() : Frame("PRIV"), d(new PrivateFramePrivate()) {}
d(new PrivateFramePrivate()) {
}
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data), PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data), d(new PrivateFramePrivate()) {
d(new PrivateFramePrivate()) {
setData(data); setData(data);
} }
@@ -82,6 +79,7 @@ void PrivateFrame::setData(const ByteVector &data) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void PrivateFrame::parseFields(const ByteVector &data) { void PrivateFrame::parseFields(const ByteVector &data) {
if (data.size() < 2) { if (data.size() < 2) {
debug("A private frame must contain at least 2 bytes."); debug("A private frame must contain at least 2 bytes.");
return; return;
@@ -94,9 +92,11 @@ void PrivateFrame::parseFields(const ByteVector &data) {
d->owner = String(data.mid(0, endOfOwner)); d->owner = String(data.mid(0, endOfOwner));
d->data = data.mid(endOfOwner + 1); d->data = data.mid(endOfOwner + 1);
} }
ByteVector PrivateFrame::renderFields() const { ByteVector PrivateFrame::renderFields() const {
ByteVector v; ByteVector v;
v.append(d->owner.data(String::Latin1)); v.append(d->owner.data(String::Latin1));
@@ -104,13 +104,13 @@ ByteVector PrivateFrame::renderFields() const {
v.append(d->data); v.append(d->data);
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h), PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h), d(new PrivateFramePrivate()) {
d(new PrivateFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -32,7 +32,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An implementation of ID3v2 privateframe //! An implementation of ID3v2 privateframe
@@ -42,49 +41,49 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
public: public:
/*! /*!
* Construct an empty private frame. * Construct an empty private frame.
*/ */
PrivateFrame(); PrivateFrame();
/*! /*!
* Construct a private frame based on the data in \a data. * Construct a private frame based on the data in \a data.
* *
* \note This is the constructor used when parsing the frame from a file. * \note This is the constructor used when parsing the frame from a file.
*/ */
explicit PrivateFrame(const ByteVector &data); explicit PrivateFrame(const ByteVector &data);
/*! /*!
* Destroys this private frame instance. * Destroys this private frame instance.
*/ */
virtual ~PrivateFrame(); virtual ~PrivateFrame();
/*! /*!
* Returns the text of this private frame, currently just the owner. * Returns the text of this private frame, currently just the owner.
* *
* \see text() * \see text()
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* \return The owner of the private frame. * \return The owner of the private frame.
* \note This should contain an email address or link to a website. * \note This should contain an email address or link to a website.
*/ */
String owner() const; String owner() const;
/*! /*!
* *
*/ */
ByteVector data() const; ByteVector data() const;
/*! /*!
* Sets the owner of the frame to \a s. * Sets the owner of the frame to \a s.
* \note This should contain an email address or link to a website. * \note This should contain an email address or link to a website.
*/ */
void setOwner(const String &s); void setOwner(const String &s);
/*! /*!
* *
*/ */
void setData(const ByteVector &v); void setData(const ByteVector &v);
protected: protected:
@@ -95,8 +94,8 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
PrivateFrame(const ByteVector &data, Header *h); PrivateFrame(const ByteVector &data, Header *h);
PrivateFrame(const PrivateFrame &); PrivateFrame(const PrivateFrame &);
@@ -109,4 +108,5 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -49,12 +49,9 @@ class RelativeVolumeFrame::RelativeVolumeFramePrivate {
// public members // public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2"), RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2"), d(new RelativeVolumeFramePrivate()) {}
d(new RelativeVolumeFramePrivate()) {
}
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data), RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data), d(new RelativeVolumeFramePrivate()) {
d(new RelativeVolumeFramePrivate()) {
setData(data); setData(data);
} }
@@ -67,6 +64,7 @@ String RelativeVolumeFrame::toString() const {
} }
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const { List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const {
List<ChannelType> l; List<ChannelType> l;
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin(); Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
@@ -74,17 +72,7 @@ List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const {
l.append((*it).first); l.append((*it).first);
return l; return l;
}
// deprecated
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const {
return MasterVolume;
}
// deprecated
void RelativeVolumeFrame::setChannelType(ChannelType) {
} }
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const { short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const {
@@ -148,6 +136,7 @@ void RelativeVolumeFrame::setIdentification(const String &s) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void RelativeVolumeFrame::parseFields(const ByteVector &data) { void RelativeVolumeFrame::parseFields(const ByteVector &data) {
int pos = 0; int pos = 0;
d->identification = readStringField(data, String::Latin1, &pos); d->identification = readStringField(data, String::Latin1, &pos);
@@ -170,9 +159,11 @@ void RelativeVolumeFrame::parseFields(const ByteVector &data) {
channel.peakVolume.peakVolume = data.mid(pos, bytes); channel.peakVolume.peakVolume = data.mid(pos, bytes);
pos += bytes; pos += bytes;
} }
} }
ByteVector RelativeVolumeFrame::renderFields() const { ByteVector RelativeVolumeFrame::renderFields() const {
ByteVector data; ByteVector data;
data.append(d->identification.data(String::Latin1)); data.append(d->identification.data(String::Latin1));
@@ -191,13 +182,13 @@ ByteVector RelativeVolumeFrame::renderFields() const {
} }
return data; return data;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// private members // private members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h), RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h), d(new RelativeVolumeFramePrivate()) {
d(new RelativeVolumeFramePrivate()) {
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -32,28 +32,24 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! An ID3v2 relative volume adjustment frame implementation //! An ID3v2 relative volume adjustment frame implementation
/*! /*!
* This is an implementation of ID3v2 relative volume adjustment. The * This is an implementation of ID3v2 relative volume adjustment.
* presence of this frame makes it possible to specify an increase in volume * The presence of this frame makes it possible to specify an increase in volume for an audio file or specific audio tracks in that file.
* for an audio file or specific audio tracks in that file. *
* * Multiple relative volume adjustment frames may be present in the tag each with a unique identification and describing volume adjustment for different channel types.
* Multiple relative volume adjustment frames may be present in the tag */
* each with a unique identification and describing volume adjustment for
* different channel types.
*/
class TAGLIB_EXPORT RelativeVolumeFrame : public Frame { class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* This indicates the type of volume adjustment that should be applied. * This indicates the type of volume adjustment that should be applied.
*/ */
enum ChannelType { enum ChannelType {
//! A type not enumerated below //! A type not enumerated below
Other = 0x00, Other = 0x00,
@@ -78,149 +74,125 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
//! Struct that stores the relevant values for ID3v2 peak volume //! Struct that stores the relevant values for ID3v2 peak volume
/*! /*!
* The peak volume is described as a series of bits that is padded to fill * The peak volume is described as a series of bits that is padded to fill a block of bytes.
* a block of bytes. These two values should always be updated in tandem. * These two values should always be updated in tandem.
*/ */
struct PeakVolume { struct PeakVolume {
/*! /*!
* Constructs an empty peak volume description. * Constructs an empty peak volume description.
*/ */
PeakVolume() : bitsRepresentingPeak(0) {} PeakVolume() : bitsRepresentingPeak(0) {}
/*! /*!
* The number of bits (in the range of 0 to 255) used to describe the * The number of bits (in the range of 0 to 255) used to describe the peak volume.
* peak volume. */
*/
unsigned char bitsRepresentingPeak; unsigned char bitsRepresentingPeak;
/*! /*!
* The array of bits (represented as a series of bytes) used to describe * The array of bits (represented as a series of bytes) used to describe the peak volume.
* the peak volume. */
*/
ByteVector peakVolume; ByteVector peakVolume;
}; };
/*! /*!
* Constructs a RelativeVolumeFrame. The relevant data should be set * Constructs a RelativeVolumeFrame. The relevant data should be set manually.
* manually. */
*/
RelativeVolumeFrame(); RelativeVolumeFrame();
/*! /*!
* Constructs a RelativeVolumeFrame based on the contents of \a data. * Constructs a RelativeVolumeFrame based on the contents of \a data.
*/ */
RelativeVolumeFrame(const ByteVector &data); RelativeVolumeFrame(const ByteVector &data);
/*! /*!
* Destroys the RelativeVolumeFrame instance. * Destroys the RelativeVolumeFrame instance.
*/ */
virtual ~RelativeVolumeFrame(); virtual ~RelativeVolumeFrame();
/*! /*!
* Returns the frame's identification. * Returns the frame's identification.
* *
* \see identification() * \see identification()
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns a list of channels with information currently in the frame. * Returns a list of channels with information currently in the frame.
*/ */
List<ChannelType> channels() const; List<ChannelType> channels() const;
/*!
* \deprecated Always returns master volume.
*/
TAGLIB_DEPRECATED ChannelType channelType() const;
/*!
* \deprecated This method no longer has any effect.
*/
TAGLIB_DEPRECATED void setChannelType(ChannelType t);
/* /*
* There was a terrible API goof here, and while this can't be changed to * There was a terrible API goof here, and while this can't be changed to the way it appears below for binary compatibility reasons, let's at least pretend that it looks clean.
* the way it appears below for binary compatibility reasons, let's at */
* least pretend that it looks clean.
*/
#ifdef DOXYGEN #ifdef DOXYGEN
/*! /*!
* Returns the relative volume adjustment "index". As indicated by the * Returns the relative volume adjustment "index".
* ID3v2 standard this is a 16-bit signed integer that reflects the * As indicated by the ID3v2 standard this is a 16-bit signed integer that reflects the decibels of adjustment when divided by 512.
* decibels of adjustment when divided by 512. *
* * This defaults to returning the value for the master volume channel if available and returns 0 if the specified channel does not exist.
* This defaults to returning the value for the master volume channel if *
* available and returns 0 if the specified channel does not exist. * \see setVolumeAdjustmentIndex()
* * \see volumeAjustment()
* \see setVolumeAdjustmentIndex() */
* \see volumeAjustment()
*/
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const; short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
/*! /*!
* Set the volume adjustment to \a index. As indicated by the ID3v2 * Set the volume adjustment to \a index.
* standard this is a 16-bit signed integer that reflects the decibels of * As indicated by the ID3v2 standard this is a 16-bit signed integer that reflects the decibels of adjustment when divided by 512.
* adjustment when divided by 512. *
* * By default this sets the value for the master volume.
* By default this sets the value for the master volume. *
* * \see volumeAdjustmentIndex()
* \see volumeAdjustmentIndex() * \see setVolumeAjustment()
* \see setVolumeAjustment() */
*/
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume); void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);
/*! /*!
* Returns the relative volume adjustment in decibels. * Returns the relative volume adjustment in decibels.
* *
* \note Because this is actually stored internally as an "index" to this * \note Because this is actually stored internally as an "index" to this
* value the value returned by this method may not be identical to the * value the value returned by this method may not be identical to the value set using setVolumeAdjustment().
* value set using setVolumeAdjustment(). *
* * This defaults to returning the value for the master volume channel if available and returns 0 if the specified channel does not exist.
* This defaults to returning the value for the master volume channel if *
* available and returns 0 if the specified channel does not exist. * \see setVolumeAdjustment()
* * \see volumeAdjustmentIndex()
* \see setVolumeAdjustment() */
* \see volumeAdjustmentIndex()
*/
float volumeAdjustment(ChannelType type = MasterVolume) const; float volumeAdjustment(ChannelType type = MasterVolume) const;
/*! /*!
* Set the relative volume adjustment in decibels to \a adjustment. * Set the relative volume adjustment in decibels to \a adjustment.
* *
* By default this sets the value for the master volume. * By default this sets the value for the master volume.
* *
* \note Because this is actually stored internally as an "index" to this * \note Because this is actually stored internally as an "index" to this value the value set by this method may not be identical to the one returned by volumeAdjustment().
* value the value set by this method may not be identical to the one *
* returned by volumeAdjustment(). * \see setVolumeAdjustment()
* * \see volumeAdjustmentIndex()
* \see setVolumeAdjustment() */
* \see volumeAdjustmentIndex()
*/
void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume); void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume);
/*! /*!
* Returns the peak volume (represented as a length and a string of bits). * Returns the peak volume (represented as a length and a string of bits).
* *
* This defaults to returning the value for the master volume channel if * This defaults to returning the value for the master volume channel if available and returns 0 if the specified channel does not exist.
* available and returns 0 if the specified channel does not exist. *
* * \see setPeakVolume()
* \see setPeakVolume() */
*/
PeakVolume peakVolume(ChannelType type = MasterVolume) const; PeakVolume peakVolume(ChannelType type = MasterVolume) const;
/*! /*!
* Sets the peak volume to \a peak. * Sets the peak volume to \a peak.
* *
* By default this sets the value for the master volume. * By default this sets the value for the master volume.
* *
* \see peakVolume() * \see peakVolume()
*/ */
void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume); void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume);
#else #else
// BIC: Combine each of the following pairs of functions (or maybe just // BIC: Combine each of the following pairs of functions (or maybe just rework this junk altogether).
// rework this junk altogether).
short volumeAdjustmentIndex(ChannelType type) const; short volumeAdjustmentIndex(ChannelType type) const;
short volumeAdjustmentIndex() const; short volumeAdjustmentIndex() const;
@@ -243,15 +215,14 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
#endif #endif
/*! /*!
* Returns the identification for this frame. * Returns the identification for this frame.
*/ */
String identification() const; String identification() const;
/*! /*!
* Sets the identification of the frame to \a s. The string * Sets the identification of the frame to \a s.
* is used to identify the situation and/or device where this * The string is used to identify the situation and/or device where this adjustment should apply.
* adjustment should apply. */
*/
void setIdentification(const String &s); void setIdentification(const String &s);
protected: protected:
@@ -270,4 +241,5 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -123,6 +123,7 @@ void SynchronizedLyricsFrame::setSynchedText(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void SynchronizedLyricsFrame::parseFields(const ByteVector &data) { void SynchronizedLyricsFrame::parseFields(const ByteVector &data) {
const int end = data.size(); const int end = data.size();
if (end < 7) { if (end < 7) {
debug("A synchronized lyrics frame must contain at least 7 bytes."); debug("A synchronized lyrics frame must contain at least 7 bytes.");
@@ -177,9 +178,11 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) {
d->synchedText.append(SynchedText(time, text)); d->synchedText.append(SynchedText(time, text));
} }
} }
ByteVector SynchronizedLyricsFrame::renderFields() const { ByteVector SynchronizedLyricsFrame::renderFields() const {
ByteVector v; ByteVector v;
String::Type encoding = d->textEncoding; String::Type encoding = d->textEncoding;
@@ -207,6 +210,7 @@ ByteVector SynchronizedLyricsFrame::renderFields() const {
} }
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -31,20 +31,19 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
//! ID3v2 synchronized lyrics frame //! ID3v2 synchronized lyrics frame
/*! /*!
* An implementation of ID3v2 synchronized lyrics. * An implementation of ID3v2 synchronized lyrics.
*/ */
class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame { class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Specifies the timestamp format used. * Specifies the timestamp format used.
*/ */
enum TimestampFormat { enum TimestampFormat {
//! The timestamp is of unknown format. //! The timestamp is of unknown format.
Unknown = 0x00, Unknown = 0x00,
@@ -57,8 +56,8 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
}; };
/*! /*!
* Specifies the type of text contained. * Specifies the type of text contained.
*/ */
enum Type { enum Type {
//! The text is some other type of text. //! The text is some other type of text.
Other = 0x00, Other = 0x00,
@@ -81,8 +80,8 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
}; };
/*! /*!
* Single entry of time stamp and lyrics text. * Single entry of time stamp and lyrics text.
*/ */
struct SynchedText { struct SynchedText {
SynchedText(unsigned int ms, String str) : time(ms), text(str) {} SynchedText(unsigned int ms, String str) : time(ms), text(str) {}
unsigned int time; unsigned int time;
@@ -90,121 +89,117 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
}; };
/*! /*!
* List of synchronized lyrics. * List of synchronized lyrics.
*/ */
typedef Strawberry_TagLib::TagLib::List<SynchedText> SynchedTextList; typedef Strawberry_TagLib::TagLib::List<SynchedText> SynchedTextList;
/*! /*!
* Construct an empty synchronized lyrics frame that will use the text * Construct an empty synchronized lyrics frame that will use the text encoding \a encoding.
* encoding \a encoding. */
*/
explicit SynchronizedLyricsFrame(String::Type encoding = String::Latin1); explicit SynchronizedLyricsFrame(String::Type encoding = String::Latin1);
/*! /*!
* Construct a synchronized lyrics frame based on the data in \a data. * Construct a synchronized lyrics frame based on the data in \a data.
*/ */
explicit SynchronizedLyricsFrame(const ByteVector &data); explicit SynchronizedLyricsFrame(const ByteVector &data);
/*! /*!
* Destroys this SynchronizedLyricsFrame instance. * Destroys this SynchronizedLyricsFrame instance.
*/ */
virtual ~SynchronizedLyricsFrame(); virtual ~SynchronizedLyricsFrame();
/*! /*!
* Returns the description of this synchronized lyrics frame. * Returns the description of this synchronized lyrics frame.
* *
* \see description() * \see description()
*/ */
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the text encoding that will be used in rendering this frame. * Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor * This defaults to the type that was either specified in the constructor or read from the frame when parsed.
* or read from the frame when parsed. *
* * \see setTextEncoding()
* \see setTextEncoding() * \see render()
* \see render() */
*/
String::Type textEncoding() const; String::Type textEncoding() const;
/*! /*!
* Returns the language encoding as a 3 byte encoding as specified by * Returns the language encoding as a 3 byte encoding as specified by
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>. * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
* *
* \note Most taggers simply ignore this value. * \note Most taggers simply ignore this value.
* *
* \see setLanguage() * \see setLanguage()
*/ */
ByteVector language() const; ByteVector language() const;
/*! /*!
* Returns the timestamp format. * Returns the timestamp format.
*/ */
TimestampFormat timestampFormat() const; TimestampFormat timestampFormat() const;
/*! /*!
* Returns the type of text contained. * Returns the type of text contained.
*/ */
Type type() const; Type type() const;
/*! /*!
* Returns the description of this synchronized lyrics frame. * Returns the description of this synchronized lyrics frame.
* *
* \note Most taggers simply ignore this value. * \note Most taggers simply ignore this value.
* *
* \see setDescription() * \see setDescription()
*/ */
String description() const; String description() const;
/*! /*!
* Returns the text with the time stamps. * Returns the text with the time stamps.
*/ */
SynchedTextList synchedText() const; SynchedTextList synchedText() const;
/*! /*!
* Sets the text encoding to be used when rendering this frame to * Sets the text encoding to be used when rendering this frame to \a encoding.
* \a encoding. *
* * \see textEncoding()
* \see textEncoding() * \see render()
* \see render() */
*/
void setTextEncoding(String::Type encoding); void setTextEncoding(String::Type encoding);
/*! /*!
* Set the language using the 3 byte language code from * Set the language using the 3 byte language code from
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to \a languageCode.
* \a languageCode. *
* * \see language()
* \see language() */
*/
void setLanguage(const ByteVector &languageCode); void setLanguage(const ByteVector &languageCode);
/*! /*!
* Set the timestamp format. * Set the timestamp format.
* *
* \see timestampFormat() * \see timestampFormat()
*/ */
void setTimestampFormat(TimestampFormat f); void setTimestampFormat(TimestampFormat f);
/*! /*!
* Set the type of text contained. * Set the type of text contained.
* *
* \see type() * \see type()
*/ */
void setType(Type t); void setType(Type t);
/*! /*!
* Sets the description of the synchronized lyrics frame to \a s. * Sets the description of the synchronized lyrics frame to \a s.
* *
* \see description() * \see description()
*/ */
void setDescription(const String &s); void setDescription(const String &s);
/*! /*!
* Sets the text with the time stamps. * Sets the text with the time stamps.
* *
* \see text() * \see text()
*/ */
void setSynchedText(const SynchedTextList &t); void setSynchedText(const SynchedTextList &t);
protected: protected:
@@ -215,8 +210,8 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
private: private:
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
SynchronizedLyricsFrame(const ByteVector &data, Header *h); SynchronizedLyricsFrame(const ByteVector &data, Header *h);
SynchronizedLyricsFrame(const SynchronizedLyricsFrame &); SynchronizedLyricsFrame(const SynchronizedLyricsFrame &);
SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &); SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &);
@@ -228,4 +223,5 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

View File

@@ -34,9 +34,7 @@ using namespace ID3v2;
class TableOfContentsFrame::TableOfContentsFramePrivate { class TableOfContentsFrame::TableOfContentsFramePrivate {
public: public:
TableOfContentsFramePrivate() : tagHeader(0), TableOfContentsFramePrivate() : tagHeader(nullptr), isTopLevel(false), isOrdered(false) {
isTopLevel(false),
isOrdered(false) {
embeddedFrameList.setAutoDelete(true); embeddedFrameList.setAutoDelete(true);
} }
@@ -69,6 +67,7 @@ ByteVectorList &strip(ByteVectorList &l) {
} }
return l; return l;
} }
} // namespace } // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -81,16 +80,15 @@ TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const
setData(data); setData(data);
} }
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID, TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID, const ByteVectorList &children, const FrameList &embeddedFrames) : ID3v2::Frame("CTOC"), d(new TableOfContentsFramePrivate()) {
const ByteVectorList &children,
const FrameList &embeddedFrames) : ID3v2::Frame("CTOC"),
d(new TableOfContentsFramePrivate()) {
d->elementID = elementID; d->elementID = elementID;
strip(d->elementID); strip(d->elementID);
d->childElements = children; d->childElements = children;
for (FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it) for (FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
addEmbeddedFrame(*it); addEmbeddedFrame(*it);
} }
TableOfContentsFrame::~TableOfContentsFrame() { TableOfContentsFrame::~TableOfContentsFrame() {
@@ -167,6 +165,7 @@ void TableOfContentsFrame::addEmbeddedFrame(Frame *frame) {
} }
void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del) { void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del) {
// remove the frame from the frame list // remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame); FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it); d->embeddedFrameList.erase(it);
@@ -178,15 +177,19 @@ void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del) {
// ...and delete as desired // ...and delete as desired
if (del) if (del)
delete frame; delete frame;
} }
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id) { void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id) {
FrameList l = d->embeddedFrameListMap[id]; FrameList l = d->embeddedFrameListMap[id];
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeEmbeddedFrame(*it, true); removeEmbeddedFrame(*it, true);
} }
String TableOfContentsFrame::toString() const { String TableOfContentsFrame::toString() const {
String s = String(d->elementID) + String s = String(d->elementID) +
": top level: " + (d->isTopLevel ? "true" : "false") + ": top level: " + (d->isTopLevel ? "true" : "false") +
", ordered: " + (d->isOrdered ? "true" : "false"); ", ordered: " + (d->isOrdered ? "true" : "false");
@@ -205,19 +208,21 @@ String TableOfContentsFrame::toString() const {
} }
return s; return s;
} }
PropertyMap TableOfContentsFrame::asProperties() const { PropertyMap TableOfContentsFrame::asProperties() const {
PropertyMap map; PropertyMap map;
map.unsupportedData().append(frameID() + String("/") + d->elementID); map.unsupportedData().append(frameID() + String("/") + d->elementID);
return map; return map;
} }
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag, TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) { // static
const ByteVector &eID) // static
{
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC"); ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin(); for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
@@ -229,10 +234,11 @@ TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *ta
} }
return nullptr; return nullptr;
} }
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) { // static
{
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC"); ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin(); for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
@@ -244,9 +250,11 @@ TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag)
} }
return nullptr; return nullptr;
} }
void TableOfContentsFrame::parseFields(const ByteVector &data) { void TableOfContentsFrame::parseFields(const ByteVector &data) {
unsigned int size = data.size(); unsigned int size = data.size();
if (size < 6) { if (size < 6) {
debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by " debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by "
@@ -286,9 +294,11 @@ void TableOfContentsFrame::parseFields(const ByteVector &data) {
embPos += frame->size() + header()->size(); embPos += frame->size() + header()->size();
addEmbeddedFrame(frame); addEmbeddedFrame(frame);
} }
} }
ByteVector TableOfContentsFrame::renderFields() const { ByteVector TableOfContentsFrame::renderFields() const {
ByteVector data; ByteVector data;
data.append(d->elementID); data.append(d->elementID);
@@ -311,11 +321,10 @@ ByteVector TableOfContentsFrame::renderFields() const {
data.append((*it2)->render()); data.append((*it2)->render());
return data; return data;
} }
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h), d(new TableOfContentsFramePrivate()) {
const ByteVector &data, Header *h) : Frame(h),
d(new TableOfContentsFramePrivate()) {
d->tagHeader = tagHeader; d->tagHeader = tagHeader;
parseFields(fieldData(data)); parseFields(fieldData(data));
} }

View File

@@ -33,13 +33,12 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
/*! /*!
* This is an implementation of ID3v2 table of contents frames. Purpose * This is an implementation of ID3v2 table of contents frames.
* of this frame is to allow a table of contents to be defined. * Purpose of this frame is to allow a table of contents to be defined.
*/ */
//! An implementation of ID3v2 table of contents frames //! An implementation of ID3v2 table of contents frames
@@ -48,176 +47,159 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
public: public:
/*! /*!
* Creates a table of contents frame based on \a data. \a tagHeader is * Creates a table of contents frame based on \a data.
* required as the internal frames are parsed based on the tag version. * \a tagHeader is required as the internal frames are parsed based on the tag version.
*/ */
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data); TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*! /*!
* Creates a table of contents frame with the element ID \a elementID, * Creates a table of contents frame with the element ID \a elementID,
* the child elements \a children and embedded frames, which become owned * the child elements \a children and embedded frames, which become owned by this frame, in \a embeddedFrames.
* by this frame, in \a embeddedFrames. */
*/
TableOfContentsFrame(const ByteVector &elementID, TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children = ByteVectorList(), const ByteVectorList &children = ByteVectorList(),
const FrameList &embeddedFrames = FrameList()); const FrameList &embeddedFrames = FrameList());
/*! /*!
* Destroys the frame. * Destroys the frame.
*/ */
~TableOfContentsFrame(); ~TableOfContentsFrame();
/*! /*!
* Returns the elementID of the frame. Element ID * Returns the elementID of the frame.
* is a null terminated string, however it's not human-readable. * Element ID is a null terminated string, however it's not human-readable.
* *
* \see setElementID() * \see setElementID()
*/ */
ByteVector elementID() const; ByteVector elementID() const;
/*! /*!
* Returns true, if the frame is top-level (doesn't have * Returns true, if the frame is top-level (doesn't have any parent CTOC frame).
* any parent CTOC frame). *
* * \see setIsTopLevel()
* \see setIsTopLevel() */
*/
bool isTopLevel() const; bool isTopLevel() const;
/*! /*!
* Returns true, if the child elements list entries * Returns true, if the child elements list entries are ordered.
* are ordered. *
* * \see setIsOrdered()
* \see setIsOrdered() */
*/
bool isOrdered() const; bool isOrdered() const;
/*! /*!
* Returns count of child elements of the frame. It always * Returns count of child elements of the frame. It always corresponds to size of child elements list.
* corresponds to size of child elements list. *
* * \see childElements()
* \see childElements() */
*/
unsigned int entryCount() const; unsigned int entryCount() const;
/*! /*!
* Returns list of child elements of the frame. * Returns list of child elements of the frame.
* *
* \see setChildElements() * \see setChildElements()
*/ */
ByteVectorList childElements() const; ByteVectorList childElements() const;
/*! /*!
* Sets the elementID of the frame to \a eID. If \a eID isn't * Sets the elementID of the frame to \a eID. If \a eID isn't null terminated, a null char is appended automatically.
* null terminated, a null char is appended automatically. *
* * \see elementID()
* \see elementID() */
*/
void setElementID(const ByteVector &eID); void setElementID(const ByteVector &eID);
/*! /*!
* Sets, if the frame is top-level (doesn't have * Sets, if the frame is top-level (doesn't have any parent CTOC frame).
* any parent CTOC frame). *
* * \see isTopLevel()
* \see isTopLevel() */
*/
void setIsTopLevel(const bool &t); void setIsTopLevel(const bool &t);
/*! /*!
* Sets, if the child elements list entries * Sets, if the child elements list entries are ordered.
* are ordered. *
* * \see isOrdered()
* \see isOrdered() */
*/
void setIsOrdered(const bool &o); void setIsOrdered(const bool &o);
/*! /*!
* Sets list of child elements of the frame to \a l. * Sets list of child elements of the frame to \a l.
* *
* \see childElements() * \see childElements()
*/ */
void setChildElements(const ByteVectorList &l); void setChildElements(const ByteVectorList &l);
/*! /*!
* Adds \a cE to list of child elements of the frame. * Adds \a cE to list of child elements of the frame.
* *
* \see childElements() * \see childElements()
*/ */
void addChildElement(const ByteVector &cE); void addChildElement(const ByteVector &cE);
/*! /*!
* Removes \a cE to list of child elements of the frame. * Removes \a cE to list of child elements of the frame.
* *
* \see childElements() * \see childElements()
*/ */
void removeChildElement(const ByteVector &cE); void removeChildElement(const ByteVector &cE);
/*! /*!
* Returns a reference to the frame list map. This is an FrameListMap of * Returns a reference to the frame list map.
* all of the frames embedded in the CTOC frame. * This is an FrameListMap of all of the frames embedded in the CTOC frame.
* *
* This is the most convenient structure for accessing the CTOC frame's * This is the most convenient structure for accessing the CTOC frame's embedded frames.
* embedded frames. Many frame types allow multiple instances of the same * Many frame types allow multiple instances of the same frame type so this is a map of lists.
* frame type so this is a map of lists. In most cases however there will * In most cases however there will only be a single frame of a certain type.
* only be a single frame of a certain type. *
* * \warning You should not modify this data structure directly, instead use addEmbeddedFrame() and removeEmbeddedFrame().
* \warning You should not modify this data structure directly, instead *
* use addEmbeddedFrame() and removeEmbeddedFrame(). * \see embeddedFrameList()
* */
* \see embeddedFrameList()
*/
const FrameListMap &embeddedFrameListMap() const; const FrameListMap &embeddedFrameListMap() const;
/*! /*!
* Returns a reference to the embedded frame list. This is an FrameList * Returns a reference to the embedded frame list.
* of all of the frames embedded in the CTOC frame in the order that they * This is an FrameList of all of the frames embedded in the CTOC frame in the order that they were parsed.
* were parsed. *
* * This can be useful if for example you want iterate over the CTOC frame's embedded frames in the order that they occur in the CTOC frame.
* This can be useful if for example you want iterate over the CTOC frame's *
* embedded frames in the order that they occur in the CTOC frame. * \warning You should not modify this data structure directly, instead use addEmbeddedFrame() and removeEmbeddedFrame().
* */
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*/
const FrameList &embeddedFrameList() const; const FrameList &embeddedFrameList() const;
/*! /*!
* Returns the embedded frame list for frames with the id \a frameID * Returns the embedded frame list for frames with the id \a frameID or an empty list if there are no embedded frames of that type.
* or an empty list if there are no embedded frames of that type. This * This is just a convenience and is equivalent to:
* is just a convenience and is equivalent to: *
* * \code
* \code * embeddedFrameListMap()[frameID];
* embeddedFrameListMap()[frameID]; * \endcode
* \endcode *
* * \see embeddedFrameListMap()
* \see embeddedFrameListMap() */
*/
const FrameList &embeddedFrameList(const ByteVector &frameID) const; const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*! /*!
* Add an embedded frame to the CTOC frame. At this point the CTOC frame * Add an embedded frame to the CTOC frame.
* takes ownership of the embedded frame and will handle freeing its memory. * At this point the CTOC frame takes ownership of the embedded frame and will handle freeing its memory.
* *
* \note Using this method will invalidate any pointers on the list * \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
* returned by embeddedFrameList() */
*/
void addEmbeddedFrame(Frame *frame); void addEmbeddedFrame(Frame *frame);
/*! /*!
* Remove an embedded frame from the CTOC frame. If \a del is true the frame's * Remove an embedded frame from the CTOC frame.
* memory will be freed; if it is false, it must be deleted by the user. * If \a del is true the frame's memory will be freed; if it is false, it must be deleted by the user.
* *
* \note Using this method will invalidate any pointers on the list * \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
* returned by embeddedFrameList() */
*/
void removeEmbeddedFrame(Frame *frame, bool del = true); void removeEmbeddedFrame(Frame *frame, bool del = true);
/*! /*!
* Remove all embedded frames of type \a id from the CTOC frame and free their * Remove all embedded frames of type \a id from the CTOC frame and free their memory.
* memory. *
* * \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
* \note Using this method will invalidate any pointers on the list */
* returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id); void removeEmbeddedFrames(const ByteVector &id);
virtual String toString() const; virtual String toString() const;
@@ -225,21 +207,21 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
PropertyMap asProperties() const; PropertyMap asProperties() const;
/*! /*!
* CTOC frames each have a unique element ID. This searches for a CTOC * CTOC frames each have a unique element ID.
* frame with the element ID \a eID and returns a pointer to it. This * This searches for a CTOC frame with the element ID \a eID and returns a pointer to it.
* can be used to link together parent and child CTOC frames. * This can be used to link together parent and child CTOC frames.
* *
* \see elementID() * \see elementID()
*/ */
static TableOfContentsFrame *findByElementID(const Tag *tag, const ByteVector &eID); static TableOfContentsFrame *findByElementID(const Tag *tag, const ByteVector &eID);
/*! /*!
* CTOC frames each contain a flag that indicates, if CTOC frame is top-level (there isn't * CTOC frames each contain a flag that indicates,
* any frame, which contains this frame in its child elements list). Only a single frame * if CTOC frame is top-level (there isn't any frame, which contains this frame in its child elements list).
* within tag can be top-level. This searches for a top-level CTOC frame. * Only a single frame within tag can be top-level. This searches for a top-level CTOC frame.
* *
* \see isTopLevel() * \see isTopLevel()
*/ */
static TableOfContentsFrame *findTopLevel(const Tag *tag); static TableOfContentsFrame *findTopLevel(const Tag *tag);
protected: protected:
@@ -254,6 +236,7 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
class TableOfContentsFramePrivate; class TableOfContentsFramePrivate;
TableOfContentsFramePrivate *d; TableOfContentsFramePrivate *d;
}; };
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib

View File

@@ -53,8 +53,8 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : Frame
setData(data); setData(data);
} }
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) { // static
{
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL"); TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
StringList l; StringList l;
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) { for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
@@ -63,10 +63,11 @@ TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const Property
} }
frame->setText(l); frame->setText(l);
return frame; return frame;
} }
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) { // static
{
TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL"); TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL");
StringList l; StringList l;
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) { for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
@@ -77,6 +78,7 @@ TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const Property
} }
frame->setText(l); frame->setText(l);
return frame; return frame;
} }
TextIdentificationFrame::~TextIdentificationFrame() { TextIdentificationFrame::~TextIdentificationFrame() {
@@ -119,17 +121,19 @@ const char *involvedPeople[][2] = {
const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]); const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]);
} // namespace } // namespace
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() { // static
{
static KeyConversionMap m; static KeyConversionMap m;
if (m.isEmpty()) { if (m.isEmpty()) {
for (size_t i = 0; i < involvedPeopleSize; ++i) for (size_t i = 0; i < involvedPeopleSize; ++i)
m.insert(involvedPeople[i][1], involvedPeople[i][0]); m.insert(involvedPeople[i][1], involvedPeople[i][0]);
} }
return m; return m;
} }
PropertyMap TextIdentificationFrame::asProperties() const { PropertyMap TextIdentificationFrame::asProperties() const {
if (frameID() == "TIPL") if (frameID() == "TIPL")
return makeTIPLProperties(); return makeTIPLProperties();
if (frameID() == "TMCL") if (frameID() == "TMCL")
@@ -163,6 +167,7 @@ PropertyMap TextIdentificationFrame::asProperties() const {
PropertyMap ret; PropertyMap ret;
ret.insert(tagName, values); ret.insert(tagName, values);
return ret; return ret;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -170,6 +175,7 @@ PropertyMap TextIdentificationFrame::asProperties() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TextIdentificationFrame::parseFields(const ByteVector &data) { void TextIdentificationFrame::parseFields(const ByteVector &data) {
// Don't try to parse invalid frames // Don't try to parse invalid frames
if (data.size() < 2) if (data.size() < 2)
@@ -209,9 +215,11 @@ void TextIdentificationFrame::parseFields(const ByteVector &data) {
d->fieldList.append(String(*it, d->textEncoding)); d->fieldList.append(String(*it, d->textEncoding));
} }
} }
} }
ByteVector TextIdentificationFrame::renderFields() const { ByteVector TextIdentificationFrame::renderFields() const {
String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding); String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
ByteVector v; ByteVector v;
@@ -231,6 +239,7 @@ ByteVector TextIdentificationFrame::renderFields() const {
} }
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -243,6 +252,7 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header
} }
PropertyMap TextIdentificationFrame::makeTIPLProperties() const { PropertyMap TextIdentificationFrame::makeTIPLProperties() const {
PropertyMap map; PropertyMap map;
if (fieldList().size() % 2 != 0) { if (fieldList().size() % 2 != 0) {
// according to the ID3 spec, TIPL must contain an even number of entries // according to the ID3 spec, TIPL must contain an even number of entries
@@ -266,9 +276,11 @@ PropertyMap TextIdentificationFrame::makeTIPLProperties() const {
} }
} }
return map; return map;
} }
PropertyMap TextIdentificationFrame::makeTMCLProperties() const { PropertyMap TextIdentificationFrame::makeTMCLProperties() const {
PropertyMap map; PropertyMap map;
if (fieldList().size() % 2 != 0) { if (fieldList().size() % 2 != 0) {
// according to the ID3 spec, TMCL must contain an even number of entries // according to the ID3 spec, TMCL must contain an even number of entries
@@ -287,14 +299,14 @@ PropertyMap TextIdentificationFrame::makeTMCLProperties() const {
map.insert(L"PERFORMER:" + instrument, (++it)->split(",")); map.insert(L"PERFORMER:" + instrument, (++it)->split(","));
} }
return map; return map;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// UserTextIdentificationFrame public members // UserTextIdentificationFrame public members
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : TextIdentificationFrame("TXXX", encoding), UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : TextIdentificationFrame("TXXX", encoding), d(nullptr) {
d(0) {
StringList l; StringList l;
l.append(String()); l.append(String());
l.append(String()); l.append(String());
@@ -306,13 +318,13 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data)
checkFields(); checkFields();
} }
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : TextIdentificationFrame("TXXX", encoding), UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : TextIdentificationFrame("TXXX", encoding), d(nullptr) {
d(0) {
setDescription(description); setDescription(description);
setText(values); setText(values);
} }
String UserTextIdentificationFrame::toString() const { String UserTextIdentificationFrame::toString() const {
// first entry is the description itself, drop from values list // first entry is the description itself, drop from values list
StringList l = fieldList(); StringList l = fieldList();
for (StringList::Iterator it = l.begin(); it != l.end(); ++it) { for (StringList::Iterator it = l.begin(); it != l.end(); ++it) {
@@ -320,6 +332,7 @@ String UserTextIdentificationFrame::toString() const {
break; break;
} }
return "[" + description() + "] " + l.toString(); return "[" + description() + "] " + l.toString();
} }
String UserTextIdentificationFrame::description() const { String UserTextIdentificationFrame::description() const {
@@ -347,6 +360,7 @@ void UserTextIdentificationFrame::setText(const StringList &fields) {
} }
void UserTextIdentificationFrame::setDescription(const String &s) { void UserTextIdentificationFrame::setDescription(const String &s) {
StringList l = fieldList(); StringList l = fieldList();
if (l.isEmpty()) if (l.isEmpty())
@@ -355,21 +369,22 @@ void UserTextIdentificationFrame::setDescription(const String &s) {
l[0] = s; l[0] = s;
TextIdentificationFrame::setText(l); TextIdentificationFrame::setText(l);
} }
PropertyMap UserTextIdentificationFrame::asProperties() const { PropertyMap UserTextIdentificationFrame::asProperties() const {
PropertyMap map; PropertyMap map;
String tagName = txxxToKey(description()); String tagName = txxxToKey(description());
StringList v = fieldList(); StringList v = fieldList();
for (StringList::ConstIterator it = v.begin(); it != v.end(); ++it) for (StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
if (it != v.begin()) if (it != v.begin()) map.insert(tagName, *it);
map.insert(tagName, *it);
return map; return map;
} }
UserTextIdentificationFrame *UserTextIdentificationFrame::find( UserTextIdentificationFrame *UserTextIdentificationFrame::find(ID3v2::Tag *tag, const String &description) { // static
ID3v2::Tag *tag, const String &description) // static
{
FrameList l = tag->frameList("TXXX"); FrameList l = tag->frameList("TXXX");
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) { for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it); UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
@@ -377,6 +392,7 @@ UserTextIdentificationFrame *UserTextIdentificationFrame::find(
return f; return f;
} }
return nullptr; return nullptr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -388,10 +404,12 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data,
} }
void UserTextIdentificationFrame::checkFields() { void UserTextIdentificationFrame::checkFields() {
int fields = fieldList().size(); int fields = fieldList().size();
if (fields == 0) if (fields == 0)
setDescription(String()); setDescription(String());
if (fields <= 1) if (fields <= 1)
setText(String()); setText(String());
} }

View File

@@ -34,7 +34,6 @@
namespace Strawberry_TagLib { namespace Strawberry_TagLib {
namespace TagLib { namespace TagLib {
namespace ID3v2 { namespace ID3v2 {
class Tag; class Tag;
@@ -43,117 +42,111 @@ typedef Map<String, String> KeyConversionMap;
//! An ID3v2 text identification frame implementation //! An ID3v2 text identification frame implementation
/*! /*!
* This is an implementation of the most common type of ID3v2 frame -- text * This is an implementation of the most common type of ID3v2 frame -- text identification frames.
* identification frames. There are a number of variations on this. Those * There are a number of variations on this. Those enumerated in the ID3v2.4 standard are:
* enumerated in the ID3v2.4 standard are: *
* * <ul>
* <ul> * <li><b>TALB</b> Album/Movie/Show title</li>
* <li><b>TALB</b> Album/Movie/Show title</li> * <li><b>TBPM</b> BPM (beats per minute)</li>
* <li><b>TBPM</b> BPM (beats per minute)</li> * <li><b>TCOM</b> Composer</li>
* <li><b>TCOM</b> Composer</li> * <li><b>TCON</b> Content type</li>
* <li><b>TCON</b> Content type</li> * <li><b>TCOP</b> Copyright message</li>
* <li><b>TCOP</b> Copyright message</li> * <li><b>TDEN</b> Encoding time</li>
* <li><b>TDEN</b> Encoding time</li> * <li><b>TDLY</b> Playlist delay</li>
* <li><b>TDLY</b> Playlist delay</li> * <li><b>TDOR</b> Original release time</li>
* <li><b>TDOR</b> Original release time</li> * <li><b>TDRC</b> Recording time</li>
* <li><b>TDRC</b> Recording time</li> * <li><b>TDRL</b> Release time</li>
* <li><b>TDRL</b> Release time</li> * <li><b>TDTG</b> Tagging time</li>
* <li><b>TDTG</b> Tagging time</li> * <li><b>TENC</b> Encoded by</li>
* <li><b>TENC</b> Encoded by</li> * <li><b>TEXT</b> Lyricist/Text writer</li>
* <li><b>TEXT</b> Lyricist/Text writer</li> * <li><b>TFLT</b> File type</li>
* <li><b>TFLT</b> File type</li> * <li><b>TIPL</b> Involved people list</li>
* <li><b>TIPL</b> Involved people list</li> * <li><b>TIT1</b> Content group description</li>
* <li><b>TIT1</b> Content group description</li> * <li><b>TIT2</b> Title/songname/content description</li>
* <li><b>TIT2</b> Title/songname/content description</li> * <li><b>TIT3</b> Subtitle/Description refinement</li>
* <li><b>TIT3</b> Subtitle/Description refinement</li> * <li><b>TKEY</b> Initial key</li>
* <li><b>TKEY</b> Initial key</li> * <li><b>TLAN</b> Language(s)</li>
* <li><b>TLAN</b> Language(s)</li> * <li><b>TLEN</b> Length</li>
* <li><b>TLEN</b> Length</li> * <li><b>TMCL</b> Musician credits list</li>
* <li><b>TMCL</b> Musician credits list</li> * <li><b>TMED</b> Media type</li>
* <li><b>TMED</b> Media type</li> * <li><b>TMOO</b> Mood</li>
* <li><b>TMOO</b> Mood</li> * <li><b>TOAL</b> Original album/movie/show title</li>
* <li><b>TOAL</b> Original album/movie/show title</li> * <li><b>TOFN</b> Original filename</li>
* <li><b>TOFN</b> Original filename</li> * <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li>
* <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li> * <li><b>TOPE</b> Original artist(s)/performer(s)</li>
* <li><b>TOPE</b> Original artist(s)/performer(s)</li> * <li><b>TOWN</b> File owner/licensee</li>
* <li><b>TOWN</b> File owner/licensee</li> * <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li>
* <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li> * <li><b>TPE2</b> Band/orchestra/accompaniment</li>
* <li><b>TPE2</b> Band/orchestra/accompaniment</li> * <li><b>TPE3</b> Conductor/performer refinement</li>
* <li><b>TPE3</b> Conductor/performer refinement</li> * <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li>
* <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li> * <li><b>TPOS</b> Part of a set</li>
* <li><b>TPOS</b> Part of a set</li> * <li><b>TPRO</b> Produced notice</li>
* <li><b>TPRO</b> Produced notice</li> * <li><b>TPUB</b> Publisher</li>
* <li><b>TPUB</b> Publisher</li> * <li><b>TRCK</b> Track number/Position in set</li>
* <li><b>TRCK</b> Track number/Position in set</li> * <li><b>TRSN</b> Internet radio station name</li>
* <li><b>TRSN</b> Internet radio station name</li> * <li><b>TRSO</b> Internet radio station owner</li>
* <li><b>TRSO</b> Internet radio station owner</li> * <li><b>TSOA</b> Album sort order</li>
* <li><b>TSOA</b> Album sort order</li> * <li><b>TSOP</b> Performer sort order</li>
* <li><b>TSOP</b> Performer sort order</li> * <li><b>TSOT</b> Title sort order</li>
* <li><b>TSOT</b> Title sort order</li> * <li><b>TSRC</b> ISRC (international standard recording code)</li>
* <li><b>TSRC</b> ISRC (international standard recording code)</li> * <li><b>TSSE</b> Software/Hardware and settings used for encoding</li>
* <li><b>TSSE</b> Software/Hardware and settings used for encoding</li> * <li><b>TSST</b> Set subtitle</li>
* <li><b>TSST</b> Set subtitle</li> * </ul>
* </ul> *
* * The ID3v2 Frames document gives a description of each of these formats
* The ID3v2 Frames document gives a description of each of these formats * and the expected order of strings in each.
* and the expected order of strings in each. ID3v2::Header::frameID() can * ID3v2::Header::frameID() can be used to determine the frame type.
* be used to determine the frame type. *
* * \note If non-Latin1 compatible strings are used with this class,
* \note If non-Latin1 compatible strings are used with this class, even if * even if the text encoding is set to Latin1, the frame will be written using UTF8
* the text encoding is set to Latin1, the frame will be written using UTF8 * (with the encoding flag appropriately set in the output).
* (with the encoding flag appropriately set in the output). */
*/
class TAGLIB_EXPORT TextIdentificationFrame : public Frame { class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
friend class FrameFactory; friend class FrameFactory;
public: public:
/*! /*!
* Construct an empty frame of type \a type. Uses \a encoding as the * Construct an empty frame of type \a type.
* default text encoding. * Uses \a encoding as the default text encoding.
* *
* \note In this case you must specify the text encoding as it * \note In this case you must specify the text encoding as it resolves the ambiguity between constructors.
* resolves the ambiguity between constructors. *
* * \note Please see the note in the class description regarding Latin1.
* \note Please see the note in the class description regarding Latin1. */
*/
TextIdentificationFrame(const ByteVector &type, String::Type encoding); TextIdentificationFrame(const ByteVector &type, String::Type encoding);
/*! /*!
* This is a dual purpose constructor. \a data can either be binary data * This is a dual purpose constructor.
* that should be parsed or (at a minimum) the frame ID. * \a data can either be binary data that should be parsed or (at a minimum) the frame ID.
*/ */
explicit TextIdentificationFrame(const ByteVector &data); explicit TextIdentificationFrame(const ByteVector &data);
/*! /*!
* This is a special factory method to create a TIPL (involved people list) * This is a special factory method to create a TIPL (involved people list) frame from the given \a properties.
* frame from the given \a properties. Will parse key=[list of values] data * Will parse key=[list of values] data into the TIPL format as specified in the ID3 standard.
* into the TIPL format as specified in the ID3 standard. */
*/
static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties); static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);
/*! /*!
* This is a special factory method to create a TMCL (musician credits list) * This is a special factory method to create a TMCL (musician credits list) frame from the given \a properties.
* frame from the given \a properties. Will parse key=[list of values] data * Will parse key=[list of values] data into the TMCL format as specified in the ID3 standard, where key should be of the form instrumentPrefix:instrument.
* into the TMCL format as specified in the ID3 standard, where key should be */
* of the form instrumentPrefix:instrument.
*/
static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties); static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
/*! /*!
* Destroys this TextIdentificationFrame instance. * Destroys this TextIdentificationFrame instance.
*/ */
virtual ~TextIdentificationFrame(); virtual ~TextIdentificationFrame();
/*! /*!
* Text identification frames are a list of string fields. * Text identification frames are a list of string fields.
* *
* This function will accept either a StringList or a String (using the * This function will accept either a StringList or a String (using the
* StringList constructor that accepts a single String). * StringList constructor that accepts a single String).
* *
* \note This will not change the text encoding of the frame even if the * \note This will not change the text encoding of the frame even if the strings passed in are not of the same encoding.
* strings passed in are not of the same encoding. Please use * Please use setEncoding(s.type()) if you wish to change the encoding of the frame.
* setEncoding(s.type()) if you wish to change the encoding of the frame. */
*/
void setText(const StringList &l); void setText(const StringList &l);
// Reimplementations. // Reimplementations.
@@ -162,37 +155,34 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the text encoding that will be used in rendering this frame. * Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor * This defaults to the type that was either specified in the constructor or read from the frame when parsed.
* or read from the frame when parsed. *
* * \note Please see the note in the class description regarding Latin1.
* \note Please see the note in the class description regarding Latin1. *
* * \see setTextEncoding()
* \see setTextEncoding() * \see render()
* \see render() */
*/
String::Type textEncoding() const; String::Type textEncoding() const;
/*! /*!
* Sets the text encoding to be used when rendering this frame to * Sets the text encoding to be used when rendering this frame to \a encoding.
* \a encoding. *
* * \note Please see the note in the class description regarding Latin1.
* \note Please see the note in the class description regarding Latin1. *
* * \see textEncoding()
* \see textEncoding() * \see render()
* \see render() */
*/
void setTextEncoding(String::Type encoding); void setTextEncoding(String::Type encoding);
/*! /*!
* Returns a list of the strings in this frame. * Returns a list of the strings in this frame.
*/ */
StringList fieldList() const; StringList fieldList() const;
/*! /*!
* Returns a KeyConversionMap mapping a role as it would be used in a PropertyMap * Returns a KeyConversionMap mapping a role as it would be used in a PropertyMap to the corresponding key used in a TIPL ID3 frame to describe that role.
* to the corresponding key used in a TIPL ID3 frame to describe that role. */
*/
static const KeyConversionMap &involvedPeopleMap(); static const KeyConversionMap &involvedPeopleMap();
PropertyMap asProperties() const; PropertyMap asProperties() const;
@@ -204,8 +194,8 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
virtual ByteVector renderFields() const; virtual ByteVector renderFields() const;
/*! /*!
* The constructor used by the FrameFactory. * The constructor used by the FrameFactory.
*/ */
TextIdentificationFrame(const ByteVector &data, Header *h); TextIdentificationFrame(const ByteVector &data, Header *h);
private: private:
@@ -213,26 +203,25 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
TextIdentificationFrame &operator=(const TextIdentificationFrame &); TextIdentificationFrame &operator=(const TextIdentificationFrame &);
/*! /*!
* Parses the special structure of a TIPL frame * Parses the special structure of a TIPL frame
* Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER", * Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
* "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed. * "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
*/ */
PropertyMap makeTIPLProperties() const; PropertyMap makeTIPLProperties() const;
/*! /*!
* Parses the special structure of a TMCL frame. * Parses the special structure of a TMCL frame.
*/ */
PropertyMap makeTMCLProperties() const; PropertyMap makeTMCLProperties() const;
class TextIdentificationFramePrivate; class TextIdentificationFramePrivate;
TextIdentificationFramePrivate *d; TextIdentificationFramePrivate *d;
}; };
/*! /*!
* This is a specialization of text identification frames that allows for * This is a specialization of text identification frames that allows for user defined entries.
* user defined entries. Each entry has a description in addition to the * Each entry has a description in addition to the normal list of fields that a text identification frame has.
* normal list of fields that a text identification frame has. *
* * This description identifies the frame and must be unique.
* This description identifies the frame and must be unique. */
*/
//! An ID3v2 custom text identification frame implementation //! An ID3v2 custom text identification frame implementation
@@ -241,34 +230,32 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
public: public:
/*! /*!
* Constructs an empty user defined text identification frame. For this to be * Constructs an empty user defined text identification frame.
* a useful frame both a description and text must be set. * For this to be a useful frame both a description and text must be set.
*/ */
explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1); explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1);
/*! /*!
* Creates a frame based on \a data. * Creates a frame based on \a data.
*/ */
explicit UserTextIdentificationFrame(const ByteVector &data); explicit UserTextIdentificationFrame(const ByteVector &data);
/*! /*!
* Creates a user defined text identification frame with the given \a description * Creates a user defined text identification frame with the given \a description and \a values.
* and \a values. */
*/
UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8); UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8);
virtual String toString() const; virtual String toString() const;
/*! /*!
* Returns the description for this frame. * Returns the description for this frame.
*/ */
String description() const; String description() const;
/*! /*!
* Sets the description of the frame to \a s. \a s must be unique. You can * Sets the description of the frame to \a s. \a s must be unique.
* check for the presence of another user defined text frame of the same type * You can check for the presence of another user defined text frame of the same type using find() and testing for null.
* using find() and testing for null. */
*/
void setDescription(const String &s); void setDescription(const String &s);
StringList fieldList() const; StringList fieldList() const;
@@ -276,24 +263,19 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
void setText(const StringList &fields); void setText(const StringList &fields);
/*! /*!
* A UserTextIdentificationFrame is parsed into a PropertyMap as follows: * A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
* - the key is the frame's description, uppercased * - the key is the frame's description, uppercased
* - if the description contains '::', only the substring after that * - if the description contains '::', only the substring after that separator is considered as key (compatibility with exfalso)
* separator is considered as key (compatibility with exfalso) * - if the above rules don't yield a valid key (e.g. containing non-ASCII characters), the returned map will contain an entry "TXXX/<description>" in its unsupportedData() list.
* - if the above rules don't yield a valid key (e.g. containing non-ASCII * - The values will be copies of the fieldList().
* characters), the returned map will contain an entry "TXXX/<description>" * - If the description() appears as value in fieldList(), it will be omitted in the value list, in order to be compatible with TagLib which copies the description() into the fieldList().
* in its unsupportedData() list. */
* - The values will be copies of the fieldList().
* - If the description() appears as value in fieldList(), it will be omitted
* in the value list, in order to be compatible with TagLib which copies
* the description() into the fieldList().
*/
PropertyMap asProperties() const; PropertyMap asProperties() const;
/*! /*!
* Searches for the user defined text frame with the description \a description * Searches for the user defined text frame with the description \a description in \a tag.
* in \a tag. This returns null if no matching frames were found. * This returns null if no matching frames were found.
*/ */
static UserTextIdentificationFrame *find(Tag *tag, const String &description); static UserTextIdentificationFrame *find(Tag *tag, const String &description);
private: private:
@@ -310,4 +292,5 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
} // namespace ID3v2 } // namespace ID3v2
} // namespace TagLib } // namespace TagLib
} // namespace Strawberry_TagLib } // namespace Strawberry_TagLib
#endif #endif

Some files were not shown because too many files have changed in this diff Show More