Additional manual formatting to taglib sources
This commit is contained in:
parent
577b7d8ec8
commit
ef34dce4dc
|
@ -1,5 +1,6 @@
|
|||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
# Check if the size of numeric types are suitable.
|
||||
|
|
|
@ -56,10 +56,10 @@ class APE::File::FilePrivate {
|
|||
FilePrivate() : APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
ID3v2Header(0),
|
||||
ID3v2Header(nullptr),
|
||||
ID3v2Location(-1),
|
||||
ID3v2Size(0),
|
||||
properties(0) {}
|
||||
properties(nullptr) {}
|
||||
|
||||
~FilePrivate() {
|
||||
delete ID3v2Header;
|
||||
|
@ -98,16 +98,18 @@ bool APE::File::isSupported(IOStream *) {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
|
||||
d(new FilePrivate()) {
|
||||
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
|
||||
d(new FilePrivate()) {
|
||||
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
APE::File::~File() {
|
||||
|
@ -127,10 +129,12 @@ void APE::File::removeUnsupportedProperties(const StringList &properties) {
|
|||
}
|
||||
|
||||
PropertyMap APE::File::setProperties(const PropertyMap &properties) {
|
||||
|
||||
if (ID3v1Tag())
|
||||
ID3v1Tag()->setProperties(properties);
|
||||
|
||||
return APETag(true)->setProperties(properties);
|
||||
|
||||
}
|
||||
|
||||
APE::Properties *APE::File::audioProperties() const {
|
||||
|
@ -138,6 +142,7 @@ APE::Properties *APE::File::audioProperties() const {
|
|||
}
|
||||
|
||||
bool APE::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("APE::File::save() -- File is read only.");
|
||||
return false;
|
||||
|
@ -206,6 +211,7 @@ bool APE::File::save() {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
ID3v1::Tag *APE::File::ID3v1Tag(bool create) {
|
||||
|
@ -217,14 +223,16 @@ APE::Tag *APE::File::APETag(bool create) {
|
|||
}
|
||||
|
||||
void APE::File::strip(int tags) {
|
||||
|
||||
if (tags & ID3v1)
|
||||
d->tag.set(ApeID3v1Index, 0);
|
||||
d->tag.set(ApeID3v1Index, nullptr);
|
||||
|
||||
if (tags & APE)
|
||||
d->tag.set(ApeAPEIndex, 0);
|
||||
d->tag.set(ApeAPEIndex, nullptr);
|
||||
|
||||
if (!ID3v1Tag())
|
||||
APETag(true);
|
||||
|
||||
}
|
||||
|
||||
bool APE::File::hasAPETag() const {
|
||||
|
@ -240,6 +248,7 @@ bool APE::File::hasID3v1Tag() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::File::read(bool readProperties) {
|
||||
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = Utils::findID3v2(this);
|
||||
|
@ -293,4 +302,5 @@ void APE::File::read(bool readProperties) {
|
|||
|
||||
d->properties = new Properties(this, streamLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,29 +53,28 @@ class Tag;
|
|||
//! An 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
|
||||
* properties from the file.
|
||||
*/
|
||||
* This is implementation of APE metadata.
|
||||
*
|
||||
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream properties from the file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APE {
|
||||
|
||||
//! An implementation of TagLib::File with APE specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for APE 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 APE files.
|
||||
*/
|
||||
* This implements and provides an interface for APE 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 APE files.
|
||||
*
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
* This set of flags is used for various operations and is suitable for being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
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
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs an APE file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an APE file from \a stream. 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
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs an APE file from \a stream.
|
||||
* 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 responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||
* or a combination of the two.
|
||||
*/
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag or a combination of the two.
|
||||
*/
|
||||
virtual Strawberry_TagLib::TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only APE
|
||||
* will be converted to the PropertyMap.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only APE will be converted to the PropertyMap.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Removes unsupported properties. Forwards to the actual Tag's
|
||||
* removeUnsupportedProperties() function.
|
||||
*/
|
||||
* Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
|
||||
*/
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Creates an APEv2 tag if necessary. A potentially existing ID3v1
|
||||
* tag will be updated as well.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* Creates an APEv2 tag if necessary.
|
||||
* A potentially existing ID3v1 tag will be updated as well.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the APE::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the APE::Properties for this file.
|
||||
* If no audio properties were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the 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.
|
||||
*/
|
||||
* Saves the 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.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this may return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* 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. 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.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this may return a null pointer if there is no valid ID3v1 tag.
|
||||
* If \a create is true it will create 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.
|
||||
* 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.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* 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
|
||||
* 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. 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.
|
||||
*
|
||||
* \see hasAPETag()
|
||||
*/
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* 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 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.
|
||||
* 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.
|
||||
*
|
||||
* \see hasAPETag()
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it removes all tags.
|
||||
*
|
||||
* \note 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
|
||||
*/
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the file.
|
||||
* By default it removes all tags.
|
||||
*
|
||||
* \note 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
|
||||
*/
|
||||
void strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an APE tag.
|
||||
*
|
||||
* \see APETag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an APE tag.
|
||||
*
|
||||
* \see APETag()
|
||||
*/
|
||||
bool hasAPETag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
bool hasID3v1Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as an APE
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as an APE file.
|
||||
*
|
||||
* \note This method is designed to do a quick check.
|
||||
* The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
|
|
|
@ -134,10 +134,12 @@ ByteVector APE::Footer::renderFooter() const {
|
|||
}
|
||||
|
||||
ByteVector APE::Footer::renderHeader() const {
|
||||
|
||||
if (!d->headerPresent)
|
||||
return ByteVector();
|
||||
else
|
||||
return render(true);
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -145,6 +147,7 @@ ByteVector APE::Footer::renderHeader() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Footer::parse(const ByteVector &data) {
|
||||
|
||||
if (data.size() < size())
|
||||
return;
|
||||
|
||||
|
@ -169,9 +172,11 @@ void APE::Footer::parse(const ByteVector &data) {
|
|||
d->headerPresent = flags[31];
|
||||
d->footerPresent = !flags[30];
|
||||
d->isHeader = flags[29];
|
||||
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::render(bool isHeader) const {
|
||||
|
||||
ByteVector v;
|
||||
|
||||
// add the file identifier -- "APETAGEX"
|
||||
|
@ -206,4 +211,5 @@ ByteVector APE::Footer::render(bool isHeader) const {
|
|||
v.append(ByteVector::fromLongLong(0));
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
|
|
@ -37,126 +37,127 @@ namespace APE {
|
|||
//! An implementation of APE footers
|
||||
|
||||
/*!
|
||||
* This class implements APE footers (and headers). It attempts to follow, both
|
||||
* semantically and programmatically, the structure specified in
|
||||
* the APE v2.0 standard. The API is based on the properties of APE footer and
|
||||
* headers specified there.
|
||||
*/
|
||||
* This class implements APE footers (and headers).
|
||||
* It attempts to follow, both semantically and programmatically,
|
||||
* the structure specified in the APE v2.0 standard.
|
||||
* The API is based on the properties of APE footer and headers specified there.
|
||||
*
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Footer {
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty APE footer.
|
||||
*/
|
||||
* Constructs an empty APE footer.
|
||||
*/
|
||||
Footer();
|
||||
|
||||
/*!
|
||||
* Constructs an APE footer based on \a data. parse() is called
|
||||
* immediately.
|
||||
*/
|
||||
* Constructs an APE footer based on \a data. parse() is called immediately.
|
||||
*/
|
||||
Footer(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the footer.
|
||||
*/
|
||||
* Destroys the 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;
|
||||
|
||||
/*!
|
||||
* Returns true if a header is present in the tag.
|
||||
*/
|
||||
* Returns true if a header is present in the tag.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns true this is actually the header.
|
||||
*/
|
||||
* Returns true this is actually the header.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the number of items in the tag.
|
||||
*/
|
||||
* Returns the number of items in the tag.
|
||||
*/
|
||||
unsigned int itemCount() const;
|
||||
|
||||
/*!
|
||||
* Set the item count to \a s.
|
||||
* \see itemCount()
|
||||
*/
|
||||
* Set the item count to \a s.
|
||||
* \see itemCount()
|
||||
*/
|
||||
void setItemCount(unsigned int s);
|
||||
|
||||
/*!
|
||||
* Returns the tag size in bytes. 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()
|
||||
*/
|
||||
* Returns the tag size in bytes.
|
||||
* 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()
|
||||
*/
|
||||
unsigned int tagSize() const;
|
||||
|
||||
/*!
|
||||
* Returns the tag size, including if present, the header
|
||||
* size.
|
||||
*
|
||||
* \see tagSize()
|
||||
*/
|
||||
* Returns the tag size, including if present, the header
|
||||
* size.
|
||||
*
|
||||
* \see tagSize()
|
||||
*/
|
||||
unsigned int completeTagSize() const;
|
||||
|
||||
/*!
|
||||
* Set the tag size to \a s.
|
||||
* \see tagSize()
|
||||
*/
|
||||
* Set the tag size to \a s.
|
||||
* \see tagSize()
|
||||
*/
|
||||
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();
|
||||
|
||||
/*!
|
||||
* Returns the string used to identify an APE tag inside of a file.
|
||||
* Presently this is always "APETAGEX".
|
||||
*/
|
||||
* Returns the string used to identify an APE tag inside of a file.
|
||||
* Presently this is always "APETAGEX".
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
/*!
|
||||
* Sets the data that will be used as the footer. 32 bytes,
|
||||
* starting from \a data will be used.
|
||||
*/
|
||||
* Sets the data that will be used as the footer. 32 bytes,
|
||||
* starting from \a data will be used.
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Renders the footer back to binary format.
|
||||
*/
|
||||
* Renders the footer back to binary format.
|
||||
*/
|
||||
ByteVector renderFooter() const;
|
||||
|
||||
/*!
|
||||
* Renders the header corresponding to the footer. If headerPresent is
|
||||
* set to false, it returns an empty ByteVector.
|
||||
*/
|
||||
* Renders the header corresponding to the footer.
|
||||
* If headerPresent is set to false, it returns an empty ByteVector.
|
||||
*/
|
||||
ByteVector renderHeader() const;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Called by setData() to parse the footer data. It makes this information
|
||||
* available through the public API.
|
||||
*/
|
||||
* Called by setData() to parse the footer data.
|
||||
* It makes this information available through the public API.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Called by renderFooter and renderHeader
|
||||
*/
|
||||
* Called by renderFooter and renderHeader
|
||||
*/
|
||||
ByteVector render(bool isHeader) const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -33,8 +33,7 @@ using namespace APE;
|
|||
|
||||
class APE::Item::ItemPrivate {
|
||||
public:
|
||||
ItemPrivate() : type(Text),
|
||||
readOnly(false) {}
|
||||
ItemPrivate() : type(Text), readOnly(false) {}
|
||||
|
||||
Item::ItemTypes type;
|
||||
String key;
|
||||
|
@ -47,8 +46,7 @@ class APE::Item::ItemPrivate {
|
|||
// 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()) {
|
||||
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()) {
|
||||
|
||||
d->key = key;
|
||||
if (binary) {
|
||||
d->type = Binary;
|
||||
|
@ -69,24 +68,28 @@ APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new
|
|||
else {
|
||||
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() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
Item &APE::Item::operator=(const Item &item) {
|
||||
|
||||
Item(item).swap(*this);
|
||||
return *this;
|
||||
|
||||
}
|
||||
|
||||
void APE::Item::swap(Item &item) {
|
||||
|
||||
using std::swap;
|
||||
|
||||
swap(d, item.d);
|
||||
|
||||
}
|
||||
|
||||
void APE::Item::setReadOnly(bool readOnly) {
|
||||
|
@ -114,14 +117,16 @@ ByteVector APE::Item::binaryData() const {
|
|||
}
|
||||
|
||||
void APE::Item::setBinaryData(const ByteVector &value) {
|
||||
|
||||
d->type = Binary;
|
||||
d->value = value;
|
||||
d->text.clear();
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -131,30 +136,39 @@ void APE::Item::setKey(const String &key) {
|
|||
}
|
||||
|
||||
void APE::Item::setValue(const String &value) {
|
||||
|
||||
d->type = Text;
|
||||
d->text = value;
|
||||
d->value.clear();
|
||||
|
||||
}
|
||||
|
||||
void APE::Item::setValues(const StringList &value) {
|
||||
|
||||
d->type = Text;
|
||||
d->text = value;
|
||||
d->value.clear();
|
||||
|
||||
}
|
||||
|
||||
void APE::Item::appendValue(const String &value) {
|
||||
|
||||
d->type = Text;
|
||||
d->text.append(value);
|
||||
d->value.clear();
|
||||
|
||||
}
|
||||
|
||||
void APE::Item::appendValues(const StringList &values) {
|
||||
|
||||
d->type = Text;
|
||||
d->text.append(values);
|
||||
d->value.clear();
|
||||
|
||||
}
|
||||
|
||||
int APE::Item::size() const {
|
||||
|
||||
int result = 8 + d->key.size() + 1;
|
||||
switch (d->type) {
|
||||
case Text:
|
||||
|
@ -174,6 +188,7 @@ int APE::Item::size() const {
|
|||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
StringList APE::Item::toStringList() const {
|
||||
|
@ -185,13 +200,16 @@ StringList APE::Item::values() const {
|
|||
}
|
||||
|
||||
String APE::Item::toString() const {
|
||||
|
||||
if (d->type == Text && !isEmpty())
|
||||
return d->text.front();
|
||||
else
|
||||
return String();
|
||||
|
||||
}
|
||||
|
||||
bool APE::Item::isEmpty() const {
|
||||
|
||||
switch (d->type) {
|
||||
case Text:
|
||||
if (d->text.isEmpty())
|
||||
|
@ -205,9 +223,11 @@ bool APE::Item::isEmpty() const {
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void APE::Item::parse(const ByteVector &data) {
|
||||
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
|
||||
if (data.size() < 11) {
|
||||
|
@ -232,9 +252,11 @@ void APE::Item::parse(const ByteVector &data) {
|
|||
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
|
||||
else
|
||||
d->value = value;
|
||||
|
||||
}
|
||||
|
||||
ByteVector APE::Item::render() const {
|
||||
|
||||
ByteVector data;
|
||||
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
||||
ByteVector value;
|
||||
|
@ -263,4 +285,5 @@ ByteVector APE::Item::render() const {
|
|||
data.append(value);
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
|
|
@ -32,19 +32,18 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace APE {
|
||||
|
||||
//! 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 {
|
||||
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 {
|
||||
//! Item contains text information coded in UTF-8
|
||||
Text = 0,
|
||||
|
@ -54,62 +53,62 @@ class TAGLIB_EXPORT Item {
|
|||
Locator = 2
|
||||
};
|
||||
/*!
|
||||
* Constructs an empty item.
|
||||
*/
|
||||
* Constructs an empty 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
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
* 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
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys the item.
|
||||
*/
|
||||
* Destroys the 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns the key.
|
||||
*/
|
||||
* Returns the key.
|
||||
*/
|
||||
String key() const;
|
||||
|
||||
/*!
|
||||
* Returns the binary value.
|
||||
* If the item type is not \a Binary, always returns an empty ByteVector.
|
||||
*/
|
||||
* Returns the binary value.
|
||||
* If the item type is not \a Binary, always returns an empty ByteVector.
|
||||
*/
|
||||
ByteVector binaryData() const;
|
||||
|
||||
/*!
|
||||
* Set the binary value to \a value
|
||||
* The item's type will also be set to \a Binary
|
||||
*/
|
||||
* Set the binary value to \a value
|
||||
* The item's type will also be set to \a Binary
|
||||
*/
|
||||
void setBinaryData(const ByteVector &value);
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
@ -118,97 +117,90 @@ class TAGLIB_EXPORT Item {
|
|||
#endif
|
||||
|
||||
/*!
|
||||
* Sets the key for the item to \a key.
|
||||
*/
|
||||
* Sets the key for the item to \a key.
|
||||
*/
|
||||
void setKey(const String &key);
|
||||
|
||||
/*!
|
||||
* Sets the text value of the item to \a value and clears any previous contents.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
* Sets the text value of the item to \a value and clears any previous contents.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void setValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Sets the text value of the item to the list of values in \a value and clears
|
||||
* any previous contents.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
* Sets the text value of the item to the list of values in \a value and clears any previous contents.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
void setValues(const StringList &values);
|
||||
|
||||
/*!
|
||||
* Appends \a value to create (or extend) the current list of text values.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
* Appends \a value to create (or extend) the current list of text values.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void appendValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Appends \a values to extend the current list of text values.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
* Appends \a values to extend the current list of text values.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
void appendValues(const StringList &values);
|
||||
|
||||
/*!
|
||||
* Returns the size of the full item.
|
||||
*/
|
||||
* Returns the size of the full item.
|
||||
*/
|
||||
int size() const;
|
||||
|
||||
/*!
|
||||
* Returns the value as a single string. In case of multiple strings,
|
||||
* the first is returned. If the data type is not \a Text, always returns
|
||||
* an empty String.
|
||||
*/
|
||||
* Returns the value as a single string. In case of multiple strings, the first is returned.
|
||||
* If the data type is not \a Text, always returns an empty String.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
/* Remove in next binary incompatible release */
|
||||
StringList toStringList() const;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Returns the list of text values. If the data type is not \a Text, always
|
||||
* returns an empty StringList.
|
||||
*/
|
||||
* Returns the list of text values. If the data type is not \a Text, always returns an empty StringList.
|
||||
*/
|
||||
StringList values() const;
|
||||
|
||||
/*!
|
||||
* Render the item to a ByteVector.
|
||||
*/
|
||||
* Render the item to a ByteVector.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Parse the item from the ByteVector \a data.
|
||||
*/
|
||||
* Parse the item from the ByteVector \a data.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Set the item to read-only.
|
||||
*/
|
||||
* Set the item to read-only.
|
||||
*/
|
||||
void setReadOnly(bool readOnly);
|
||||
|
||||
/*!
|
||||
* Return true if the item is read-only.
|
||||
*/
|
||||
* Return true if the item is read-only.
|
||||
*/
|
||||
bool isReadOnly() const;
|
||||
|
||||
/*!
|
||||
* Sets the type of the item to \a type.
|
||||
*
|
||||
* \see ItemTypes
|
||||
*/
|
||||
* Sets the type of the item to \a type.
|
||||
*
|
||||
* \see ItemTypes
|
||||
*/
|
||||
void setType(ItemTypes type);
|
||||
|
||||
/*!
|
||||
* Returns the type of the item.
|
||||
*/
|
||||
* Returns the type of the item.
|
||||
*/
|
||||
ItemTypes type() const;
|
||||
|
||||
/*!
|
||||
* Returns if the item has any real content.
|
||||
*/
|
||||
* Returns if the item has any real content.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
|
@ -216,7 +208,6 @@ class TAGLIB_EXPORT Item {
|
|||
ItemPrivate *d;
|
||||
};
|
||||
} // namespace APE
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -61,13 +61,7 @@ class APE::Properties::PropertiesPrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Properties::Properties(File *, ReadStyle style) : AudioProperties(style),
|
||||
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()) {
|
||||
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
|
||||
read(file, streamLength);
|
||||
}
|
||||
|
||||
|
@ -75,10 +69,6 @@ APE::Properties::~Properties() {
|
|||
delete d;
|
||||
}
|
||||
|
||||
int APE::Properties::length() const {
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int APE::Properties::lengthInSeconds() const {
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
@ -125,6 +115,7 @@ int headerVersion(const ByteVector &header) {
|
|||
} // namespace
|
||||
|
||||
void APE::Properties::read(File *file, long streamLength) {
|
||||
|
||||
// First, we assume that the file pointer is set at the first descriptor.
|
||||
long offset = file->tell();
|
||||
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->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeCurrent(File *file) {
|
||||
|
||||
// Read the descriptor
|
||||
file->seek(2, File::Current);
|
||||
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 finalFrameBlocks = header.toUInt(8, false);
|
||||
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
||||
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeOld(File *file) {
|
||||
|
||||
const ByteVector header = file->readBlock(26);
|
||||
if (header.size() < 26) {
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace APE {
|
||||
|
||||
class File;
|
||||
|
@ -43,86 +42,66 @@ class File;
|
|||
//! An implementation of audio property reading for APE
|
||||
|
||||
/*!
|
||||
* This reads the data from an APE stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
* This reads the data from an APE stream found in the AudioProperties API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
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
|
||||
* APE::File \a file.
|
||||
*/
|
||||
* Create an instance of APE::Properties with the data read from the APE::File \a file.
|
||||
*/
|
||||
Properties(File *file, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this APE::Properties instance.
|
||||
*/
|
||||
* Destroys this APE::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \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()
|
||||
*/
|
||||
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInSeconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of bits per audio sample.
|
||||
*/
|
||||
* Returns the number of bits per audio sample.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns APE version.
|
||||
*/
|
||||
* Returns APE version.
|
||||
*/
|
||||
int version() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -51,7 +51,7 @@ const unsigned int MaxKeyLength = 255;
|
|||
|
||||
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)
|
||||
|
||||
|
@ -62,7 +62,7 @@ bool isKeyValid(const ByteVector &key) {
|
|||
}
|
||||
|
||||
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])
|
||||
return false;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ bool isKeyValid(const ByteVector &key) {
|
|||
|
||||
class APE::Tag::TagPrivate {
|
||||
public:
|
||||
TagPrivate() : file(0), footerLocation(0) {}
|
||||
TagPrivate() : file(nullptr), footerLocation(0) {}
|
||||
|
||||
File *file;
|
||||
long footerLocation;
|
||||
|
@ -207,6 +207,7 @@ const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions
|
|||
} // namespace
|
||||
|
||||
PropertyMap APE::Tag::properties() const {
|
||||
|
||||
PropertyMap properties;
|
||||
ItemListMap::ConstIterator it = itemListMap().begin();
|
||||
for (; it != itemListMap().end(); ++it) {
|
||||
|
@ -226,15 +227,19 @@ PropertyMap APE::Tag::properties() const {
|
|||
}
|
||||
}
|
||||
return properties;
|
||||
|
||||
}
|
||||
|
||||
void APE::Tag::removeUnsupportedProperties(const StringList &properties) {
|
||||
|
||||
StringList::ConstIterator it = properties.begin();
|
||||
for (; it != properties.end(); ++it)
|
||||
removeItem(*it);
|
||||
|
||||
}
|
||||
|
||||
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) {
|
||||
|
||||
PropertyMap properties(origProps); // make a local copy that can be modified
|
||||
|
||||
// see comment in properties()
|
||||
|
@ -280,10 +285,12 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) {
|
|||
}
|
||||
|
||||
bool APE::Tag::checkKey(const String &key) {
|
||||
|
||||
if (key.size() < MinKeyLength || key.size() > MaxKeyLength)
|
||||
return false;
|
||||
|
||||
return isKeyValid(key.data(String::UTF8));
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (replace)
|
||||
removeItem(key);
|
||||
|
||||
|
@ -314,24 +322,29 @@ void APE::Tag::addValue(const String &key, const String &value, bool replace) {
|
|||
it->second.appendValue(value);
|
||||
else
|
||||
setItem(key, Item(key, value));
|
||||
|
||||
}
|
||||
|
||||
void APE::Tag::setData(const String &key, const ByteVector &value) {
|
||||
|
||||
removeItem(key);
|
||||
|
||||
if (value.isEmpty())
|
||||
return;
|
||||
|
||||
setItem(key, Item(key, value, true));
|
||||
|
||||
}
|
||||
|
||||
void APE::Tag::setItem(const String &key, const Item &item) {
|
||||
|
||||
if (!checkKey(key)) {
|
||||
debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->itemListMap[key.upper()] = item;
|
||||
|
||||
}
|
||||
|
||||
bool APE::Tag::isEmpty() const {
|
||||
|
@ -343,6 +356,7 @@ bool APE::Tag::isEmpty() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Tag::read() {
|
||||
|
||||
if (d->file && d->file->isValid()) {
|
||||
|
||||
d->file->seek(d->footerLocation);
|
||||
|
@ -355,9 +369,11 @@ void APE::Tag::read() {
|
|||
d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
|
||||
parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector APE::Tag::render() const {
|
||||
|
||||
ByteVector data;
|
||||
unsigned int itemCount = 0;
|
||||
|
||||
|
@ -371,9 +387,11 @@ ByteVector APE::Tag::render() const {
|
|||
d->footer.setHeaderPresent(true);
|
||||
|
||||
return d->footer.renderHeader() + data + d->footer.renderFooter();
|
||||
|
||||
}
|
||||
|
||||
void APE::Tag::parse(const ByteVector &data) {
|
||||
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
|
||||
if (data.size() < 11)
|
||||
|
@ -404,4 +422,5 @@ void APE::Tag::parse(const ByteVector &data) {
|
|||
|
||||
pos += keyLength + valLegnth + 9;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ namespace APE {
|
|||
class Footer;
|
||||
|
||||
/*!
|
||||
* A mapping between a list of item names, or keys, and the associated item.
|
||||
*
|
||||
* \see APE::Tag::itemListMap()
|
||||
*/
|
||||
* A mapping between a list of item names, or keys, and the associated item.
|
||||
*
|
||||
* \see APE::Tag::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 {
|
||||
public:
|
||||
/*!
|
||||
* Create an APE tag with default values.
|
||||
*/
|
||||
* Create an APE tag with default values.
|
||||
*/
|
||||
Tag();
|
||||
|
||||
/*!
|
||||
* Create an APE tag and parse the data in \a file with APE footer at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
* Create an APE tag and parse the data in \a file with APE footer at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation);
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Renders the in memory values to a ByteVector suitable for writing to
|
||||
* the file.
|
||||
*/
|
||||
* Renders the in memory values to a ByteVector suitable for writing to the file.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the string "APETAGEX" suitable for usage in locating the tag in a
|
||||
* file.
|
||||
*/
|
||||
* Returns the string "APETAGEX" suitable for usage in locating the tag in a file.
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
// Reimplementations.
|
||||
|
@ -104,94 +102,91 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
|||
virtual void setTrack(unsigned int i);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* APE tags are perfectly compatible with the dictionary interface because they
|
||||
* support both arbitrary tag names and multiple values. 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
|
||||
* deleted on request using removeUnsupportedProperties(). The same happens
|
||||
* to Text items if their key is invalid for PropertyMap (which should actually
|
||||
* never happen).
|
||||
*
|
||||
* 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, respectively,
|
||||
* in order to be compliant with the names used in other formats.
|
||||
*/
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* APE tags are perfectly compatible with the dictionary interface because they
|
||||
* support both arbitrary tag names and multiple values.
|
||||
* 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
|
||||
* deleted on request using removeUnsupportedProperties().
|
||||
* The same happens to Text items if their key is invalid for PropertyMap (which should actually never happen).
|
||||
*
|
||||
* 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,
|
||||
* respectively, in order to be compliant with the names used in other formats.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function. 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
|
||||
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
|
||||
*/
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* 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
|
||||
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
|
||||
*/
|
||||
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 &);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's footer.
|
||||
*/
|
||||
* Returns a pointer to the tag's footer.
|
||||
*/
|
||||
Footer *footer() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the item list map. 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.
|
||||
*
|
||||
* APE tags are case-insensitive, all keys in this map have been converted
|
||||
* to upper case.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use setItem() and removeItem().
|
||||
*/
|
||||
* Returns a reference to the item list map.
|
||||
* 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.
|
||||
*
|
||||
* APE tags are case-insensitive, all keys in this map have been converted
|
||||
* to upper case.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use setItem() and removeItem().
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Adds to the text item specified by \a key the data \a value. If \a replace
|
||||
* is true, then all of the other values on the same key will be removed
|
||||
* first. If a binary item exists for \a key it will be removed first.
|
||||
*/
|
||||
* Adds to the text item specified by \a key the data \a value.
|
||||
* If \a replace is true, then all of the other values on the same key 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);
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* all of the other values on the same key will be removed.
|
||||
*/
|
||||
* 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 all of the other values on the same key will be removed.
|
||||
*/
|
||||
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
|
||||
* present, it will be replaced.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
|
|
|
@ -35,10 +35,7 @@ using namespace Strawberry_TagLib::TagLib;
|
|||
|
||||
class ASF::Attribute::AttributePrivate : public RefCounter {
|
||||
public:
|
||||
AttributePrivate() : pictureValue(ASF::Picture::fromInvalid()),
|
||||
numericValue(0),
|
||||
stream(0),
|
||||
language(0) {}
|
||||
AttributePrivate() : pictureValue(ASF::Picture::fromInvalid()), numericValue(0), stream(0), language(0) {}
|
||||
AttributeTypes type;
|
||||
String stringValue;
|
||||
ByteVector byteVectorValue;
|
||||
|
@ -146,6 +143,7 @@ ASF::Picture ASF::Attribute::toPicture() const {
|
|||
}
|
||||
|
||||
String ASF::Attribute::parse(ASF::File &f, int kind) {
|
||||
|
||||
unsigned int size, nameLength;
|
||||
String name;
|
||||
d->pictureValue = Picture::fromInvalid();
|
||||
|
@ -214,9 +212,11 @@ String ASF::Attribute::parse(ASF::File &f, int kind) {
|
|||
}
|
||||
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
int ASF::Attribute::dataSize() const {
|
||||
|
||||
switch (d->type) {
|
||||
case WordType:
|
||||
return 2;
|
||||
|
@ -236,9 +236,11 @@ int ASF::Attribute::dataSize() const {
|
|||
return d->byteVectorValue.size();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::Attribute::render(const String &name, int kind) const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
switch (d->type) {
|
||||
|
@ -296,6 +298,7 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const {
|
|||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
int ASF::Attribute::language() const {
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ASF {
|
||||
|
||||
class File;
|
||||
|
@ -42,8 +41,8 @@ class Picture;
|
|||
class TAGLIB_EXPORT Attribute {
|
||||
public:
|
||||
/*!
|
||||
* Enum of types an Attribute can have.
|
||||
*/
|
||||
* Enum of types an Attribute can have.
|
||||
*/
|
||||
enum AttributeTypes {
|
||||
UnicodeType = 0,
|
||||
BytesType = 1,
|
||||
|
@ -55,131 +54,131 @@ class TAGLIB_EXPORT Attribute {
|
|||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty attribute.
|
||||
*/
|
||||
* Constructs an empty 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
|
||||
*/
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Construct an attribute as a copy of \a other.
|
||||
*/
|
||||
* Construct an attribute as a copy of \a other.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Destroys the attribute.
|
||||
*/
|
||||
* Destroys the attribute.
|
||||
*/
|
||||
virtual ~Attribute();
|
||||
|
||||
/*!
|
||||
* Returns type of the value.
|
||||
*/
|
||||
* Returns type of the value.
|
||||
*/
|
||||
AttributeTypes type() const;
|
||||
|
||||
/*!
|
||||
* Returns the BoolType \a value.
|
||||
*/
|
||||
* Returns the BoolType \a value.
|
||||
*/
|
||||
unsigned short toBool() const;
|
||||
|
||||
/*!
|
||||
* Returns the WordType \a value.
|
||||
*/
|
||||
* Returns the WordType \a value.
|
||||
*/
|
||||
unsigned short toUShort() const;
|
||||
|
||||
/*!
|
||||
* Returns the DWordType \a value.
|
||||
*/
|
||||
* Returns the DWordType \a value.
|
||||
*/
|
||||
unsigned int toUInt() const;
|
||||
|
||||
/*!
|
||||
* Returns the QWordType \a value.
|
||||
*/
|
||||
* Returns the QWordType \a value.
|
||||
*/
|
||||
unsigned long long toULongLong() const;
|
||||
|
||||
/*!
|
||||
* Returns the UnicodeType \a value.
|
||||
*/
|
||||
* Returns the UnicodeType \a value.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the BytesType \a value.
|
||||
*/
|
||||
* Returns the BytesType \a value.
|
||||
*/
|
||||
ByteVector toByteVector() const;
|
||||
|
||||
/*!
|
||||
* Returns the Picture \a value.
|
||||
*/
|
||||
* Returns the Picture \a value.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Sets the language number.
|
||||
*/
|
||||
* Sets the language number.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Sets the stream number.
|
||||
*/
|
||||
* Sets the stream number.
|
||||
*/
|
||||
void setStream(int value);
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
@ -199,7 +198,6 @@ class TAGLIB_EXPORT Attribute {
|
|||
AttributePrivate *d;
|
||||
};
|
||||
} // namespace ASF
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -50,13 +50,13 @@ class ASF::File::FilePrivate {
|
|||
class MetadataLibraryObject;
|
||||
|
||||
FilePrivate() : headerSize(0),
|
||||
tag(0),
|
||||
properties(0),
|
||||
contentDescriptionObject(0),
|
||||
extendedContentDescriptionObject(0),
|
||||
headerExtensionObject(0),
|
||||
metadataObject(0),
|
||||
metadataLibraryObject(0) {
|
||||
tag(nullptr),
|
||||
properties(nullptr),
|
||||
contentDescriptionObject(nullptr),
|
||||
extendedContentDescriptionObject(nullptr),
|
||||
headerExtensionObject(nullptr),
|
||||
metadataObject(nullptr),
|
||||
metadataLibraryObject(nullptr) {
|
||||
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) {
|
||||
|
||||
data.clear();
|
||||
if (size > 24 && size <= (unsigned int)(file->length()))
|
||||
data = file->readBlock(size - 24);
|
||||
else
|
||||
data = ByteVector();
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/) {
|
||||
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 {
|
||||
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) {
|
||||
|
||||
BaseObject::parse(file, size);
|
||||
if (data.size() < 64) {
|
||||
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 preroll = data.toLongLong(56, false);
|
||||
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
BaseObject::parse(file, size);
|
||||
if (data.size() < 70) {
|
||||
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->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
|
||||
file->d->properties->setBitsPerSample(data.toUShort(68, false));
|
||||
|
||||
}
|
||||
|
||||
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*/) {
|
||||
|
||||
const int titleLength = readWORD(file);
|
||||
const int artistLength = 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->setComment(readString(file, commentLength));
|
||||
file->d->tag->setRating(readString(file, ratingLength));
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file) {
|
||||
|
||||
const ByteVector v1 = renderString(file->d->tag->title());
|
||||
const ByteVector v2 = renderString(file->d->tag->artist());
|
||||
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(v5);
|
||||
return BaseObject::render(file);
|
||||
|
||||
}
|
||||
|
||||
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*/) {
|
||||
|
||||
int count = readWORD(file);
|
||||
while (count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file) {
|
||||
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(""));
|
||||
return BaseObject::render(file);
|
||||
|
||||
}
|
||||
|
||||
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*/) {
|
||||
|
||||
int count = readWORD(file);
|
||||
while (count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 1);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file) {
|
||||
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(""));
|
||||
return BaseObject::render(file);
|
||||
|
||||
}
|
||||
|
||||
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*/) {
|
||||
|
||||
int count = readWORD(file);
|
||||
while (count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 2);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file) {
|
||||
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(""));
|
||||
return BaseObject::render(file);
|
||||
|
||||
}
|
||||
|
||||
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*/) {
|
||||
|
||||
file->seek(18, File::Current);
|
||||
long long dataSize = readDWORD(file);
|
||||
long long dataPos = 0;
|
||||
|
@ -366,15 +388,18 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig
|
|||
objects.append(obj);
|
||||
dataPos += size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file) {
|
||||
|
||||
data.clear();
|
||||
for (List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
|
||||
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;
|
||||
return BaseObject::render(file);
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
BaseObject::parse(file, size);
|
||||
if (data.size() <= 20) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -435,24 +462,24 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ASF::File::isSupported(IOStream *stream) {
|
||||
|
||||
// An ASF file has to start with the designated GUID.
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 16, false);
|
||||
return (id == headerGuid);
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::File::File(FileName file, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
|
||||
d(new FilePrivate()) {
|
||||
ASF::File::File(FileName file, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
|
||||
if (isOpen())
|
||||
read();
|
||||
}
|
||||
|
||||
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
|
||||
d(new FilePrivate()) {
|
||||
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
|
||||
if (isOpen())
|
||||
read();
|
||||
}
|
||||
|
@ -482,6 +509,7 @@ ASF::Properties *ASF::File::audioProperties() const {
|
|||
}
|
||||
|
||||
bool ASF::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("ASF::File::save() -- File is read only.");
|
||||
return false;
|
||||
|
@ -562,6 +590,7 @@ bool ASF::File::save() {
|
|||
d->headerSize = data.size() + 30;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -569,6 +598,7 @@ bool ASF::File::save() {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ASF::File::read() {
|
||||
|
||||
if (!isValid())
|
||||
return;
|
||||
|
||||
|
@ -594,8 +624,8 @@ void ASF::File::read() {
|
|||
}
|
||||
seek(2, Current);
|
||||
|
||||
FilePrivate::FilePropertiesObject *filePropertiesObject = 0;
|
||||
FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0;
|
||||
FilePrivate::FilePropertiesObject *filePropertiesObject = nullptr;
|
||||
FilePrivate::StreamPropertiesObject *streamPropertiesObject = nullptr;
|
||||
for (int i = 0; i < numObjects; i++) {
|
||||
const ByteVector guid = readBlock(16);
|
||||
if (guid.size() != 16) {
|
||||
|
@ -648,4 +678,5 @@ void ASF::File::read() {
|
|||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,88 +39,84 @@ namespace TagLib {
|
|||
namespace ASF {
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for ASF 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 ASF files.
|
||||
*/
|
||||
* This implements and provides an interface for ASF 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 ASF files.
|
||||
*/
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* Constructs an ASF file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*/
|
||||
* Constructs an ASF file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an ASF file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*
|
||||
* \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,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
* Constructs an ASF file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*
|
||||
* \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, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ASF tag of the file.
|
||||
*
|
||||
* ASF::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \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
|
||||
* destroyed.
|
||||
*/
|
||||
* Returns a pointer to the ASF tag of the file.
|
||||
*
|
||||
* ASF::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \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
|
||||
* destroyed.
|
||||
*/
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Removes unsupported properties. Forwards to the actual Tag's
|
||||
* removeUnsupportedProperties() function.
|
||||
*/
|
||||
* Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
|
||||
*/
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the ASF audio properties for this file.
|
||||
*/
|
||||
* Returns the ASF audio properties for this file.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as an ASF
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as an ASF file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
|
|
|
@ -76,7 +76,7 @@ ASF::Picture::Type ASF::Picture::type() const {
|
|||
return d->type;
|
||||
}
|
||||
|
||||
void ASF::Picture::setType(const ASF::Picture::Type& t) {
|
||||
void ASF::Picture::setType(const ASF::Picture::Type &t) {
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ ByteVector ASF::Picture::picture() const {
|
|||
return d->picture;
|
||||
}
|
||||
|
||||
void ASF::Picture::setPicture(const ByteVector& p) {
|
||||
void ASF::Picture::setPicture(const ByteVector &p) {
|
||||
d->picture = p;
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,7 @@ void ASF::Picture::swap(Picture& other) {
|
|||
}
|
||||
|
||||
ByteVector ASF::Picture::render() const {
|
||||
|
||||
if (!isValid())
|
||||
return ByteVector();
|
||||
|
||||
|
@ -121,9 +122,11 @@ ByteVector ASF::Picture::render() const {
|
|||
renderString(d->mimeType) +
|
||||
renderString(d->description) +
|
||||
d->picture;
|
||||
|
||||
}
|
||||
|
||||
void ASF::Picture::parse(const ByteVector& bytes) {
|
||||
void ASF::Picture::parse(const ByteVector &bytes) {
|
||||
|
||||
d->valid = false;
|
||||
if (bytes.size() < 9)
|
||||
return;
|
||||
|
@ -152,11 +155,13 @@ void ASF::Picture::parse(const ByteVector& bytes) {
|
|||
|
||||
d->picture = bytes.mid(pos, dataLen);
|
||||
d->valid = true;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
ASF::Picture ASF::Picture::fromInvalid() {
|
||||
|
||||
Picture ret;
|
||||
ret.d->valid = false;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
|
|
@ -38,18 +38,17 @@ namespace ASF {
|
|||
//! An ASF attached picture interface implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ASF attached pictures interface. Pictures may be
|
||||
* included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture
|
||||
* attribute in a single tag). These pictures are usually in either JPEG or
|
||||
* PNG format.
|
||||
* \see Attribute::toPicture()
|
||||
* \see Attribute::Attribute(const Picture& picture)
|
||||
*/
|
||||
* This is an implementation of ASF attached pictures interface.
|
||||
* Pictures may be included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture attribute in a single tag).
|
||||
* These pictures are usually in either JPEG or PNG format.
|
||||
* \see Attribute::toPicture()
|
||||
* \see Attribute::Attribute(const Picture& picture)
|
||||
*/
|
||||
class TAGLIB_EXPORT Picture {
|
||||
public:
|
||||
/*!
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
enum Type {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
|
@ -96,112 +95,109 @@ class TAGLIB_EXPORT Picture {
|
|||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty picture.
|
||||
*/
|
||||
* Constructs an empty picture.
|
||||
*/
|
||||
Picture();
|
||||
|
||||
/*!
|
||||
* Construct an picture as a copy of \a other.
|
||||
*/
|
||||
* Construct an picture as a copy of \a other.
|
||||
*/
|
||||
Picture(const Picture& other);
|
||||
|
||||
/*!
|
||||
* Destroys the picture.
|
||||
*/
|
||||
* Destroys the 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns true if Picture stores valid picture
|
||||
*/
|
||||
* Returns true if Picture stores valid picture
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
* \see setMimeType(const String &)
|
||||
* \see picture()
|
||||
* \see setPicture(const ByteArray&)
|
||||
*/
|
||||
* Returns the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
|
||||
* \see setMimeType(const String &)
|
||||
* \see picture()
|
||||
* \see setPicture(const ByteArray&)
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
* \see setMimeType(const String &)
|
||||
* \see picture()
|
||||
* \see setPicture(const ByteArray&)
|
||||
*/
|
||||
* Sets the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
|
||||
* \see setMimeType(const String &)
|
||||
* \see picture()
|
||||
* \see setPicture(const ByteArray&)
|
||||
*/
|
||||
void setMimeType(const String& value);
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
void setType(const ASF::Picture::Type& t);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setDescription(const String& desc);
|
||||
|
||||
/*!
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
ByteVector picture() const;
|
||||
|
||||
/*!
|
||||
* Sets the image data to \a p. \a p should be of the type specified in
|
||||
* this frame's mime-type specification.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
* Sets the image data to \a p.
|
||||
* \a p should be of the type specified in this frame's mime-type specification.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setPicture(const ByteVector& p);
|
||||
|
||||
/*!
|
||||
* Returns picture as binary raw data \a value
|
||||
*/
|
||||
* Returns picture as binary raw data \a value
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns picture as binary raw data \a value
|
||||
*/
|
||||
* Returns picture as binary raw data \a value
|
||||
*/
|
||||
int dataSize() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
|
|
@ -62,10 +62,6 @@ ASF::Properties::~Properties() {
|
|||
delete d;
|
||||
}
|
||||
|
||||
int ASF::Properties::length() const {
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int ASF::Properties::lengthInSeconds() const {
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
@ -135,6 +131,7 @@ void ASF::Properties::setBitsPerSample(int value) {
|
|||
}
|
||||
|
||||
void ASF::Properties::setCodec(int value) {
|
||||
|
||||
switch (value) {
|
||||
case 0x0160:
|
||||
d->codec = WMA1;
|
||||
|
@ -152,6 +149,7 @@ void ASF::Properties::setCodec(int value) {
|
|||
d->codec = Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ASF::Properties::setCodecName(const String &value) {
|
||||
|
|
|
@ -32,129 +32,116 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ASF {
|
||||
|
||||
//! An implementation of ASF audio properties
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
public:
|
||||
/*!
|
||||
* Audio codec types can be used in ASF file.
|
||||
*/
|
||||
* Audio codec types can be used in ASF file.
|
||||
*/
|
||||
enum Codec {
|
||||
/*!
|
||||
* Couldn't detect the codec.
|
||||
*/
|
||||
* Couldn't detect the codec.
|
||||
*/
|
||||
Unknown = 0,
|
||||
|
||||
/*!
|
||||
* Windows Media Audio 1
|
||||
*/
|
||||
* Windows Media Audio 1
|
||||
*/
|
||||
WMA1,
|
||||
|
||||
/*!
|
||||
* Windows Media Audio 2 or above
|
||||
*/
|
||||
* Windows Media Audio 2 or above
|
||||
*/
|
||||
WMA2,
|
||||
|
||||
/*!
|
||||
* Windows Media Audio 9 Professional
|
||||
*/
|
||||
* Windows Media Audio 9 Professional
|
||||
*/
|
||||
WMA9Pro,
|
||||
|
||||
/*!
|
||||
* Windows Media Audio 9 Lossless
|
||||
*/
|
||||
* Windows Media Audio 9 Lossless
|
||||
*/
|
||||
WMA9Lossless,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Creates an instance of ASF::Properties.
|
||||
*/
|
||||
* Creates an instance of ASF::Properties.
|
||||
*/
|
||||
Properties();
|
||||
|
||||
/*!
|
||||
* Destroys this ASF::Properties instance.
|
||||
*/
|
||||
* Destroys this ASF::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \note This method is just an alias of lengthInSeconds().
|
||||
*
|
||||
* \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()
|
||||
*/
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInSeconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of bits per audio sample.
|
||||
*/
|
||||
* Returns the number of bits per audio sample.
|
||||
*/
|
||||
int bitsPerSample() const;
|
||||
|
||||
/*!
|
||||
* Returns the codec used in the file.
|
||||
*
|
||||
* \see codecName()
|
||||
* \see codecDescription()
|
||||
*/
|
||||
* Returns the codec used in the file.
|
||||
*
|
||||
* \see codecName()
|
||||
* \see codecDescription()
|
||||
*/
|
||||
Codec codec() const;
|
||||
|
||||
/*!
|
||||
* Returns the concrete codec name, for example "Windows Media Audio 9.1"
|
||||
* used in the file if available, otherwise an empty string.
|
||||
*
|
||||
* \see codec()
|
||||
* \see codecDescription()
|
||||
*/
|
||||
* Returns the concrete codec name, for example "Windows Media Audio 9.1" used in the file if available, otherwise an empty string.
|
||||
*
|
||||
* \see codec()
|
||||
* \see codecDescription()
|
||||
*/
|
||||
String codecName() const;
|
||||
|
||||
/*!
|
||||
* Returns the codec description, typically contains the encoder settings,
|
||||
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available,
|
||||
* otherwise an empty string.
|
||||
*
|
||||
* \see codec()
|
||||
* \see codecName()
|
||||
*/
|
||||
* Returns the codec description, typically contains the encoder settings,
|
||||
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available, otherwise an empty string.
|
||||
*
|
||||
* \see codec()
|
||||
* \see codecName()
|
||||
*/
|
||||
String codecDescription() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file is encrypted.
|
||||
*/
|
||||
* Returns whether or not the file is encrypted.
|
||||
*/
|
||||
bool isEncrypted() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
|
|
@ -38,8 +38,7 @@ class ASF::Tag::TagPrivate {
|
|||
AttributeListMap attributeListMap;
|
||||
};
|
||||
|
||||
ASF::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(),
|
||||
d(new TagPrivate()) {
|
||||
ASF::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), d(new TagPrivate()) {
|
||||
}
|
||||
|
||||
ASF::Tag::~Tag() {
|
||||
|
@ -55,9 +54,11 @@ String ASF::Tag::artist() const {
|
|||
}
|
||||
|
||||
String ASF::Tag::album() const {
|
||||
|
||||
if (d->attributeListMap.contains("WM/AlbumTitle"))
|
||||
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
||||
return String();
|
||||
|
||||
}
|
||||
|
||||
String ASF::Tag::copyright() const {
|
||||
|
@ -73,12 +74,15 @@ String ASF::Tag::rating() const {
|
|||
}
|
||||
|
||||
unsigned int ASF::Tag::year() const {
|
||||
|
||||
if (d->attributeListMap.contains("WM/Year"))
|
||||
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::track() const {
|
||||
|
||||
if (d->attributeListMap.contains("WM/TrackNumber")) {
|
||||
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
|
||||
if (attr.type() == ASF::Attribute::DWordType)
|
||||
|
@ -89,12 +93,15 @@ unsigned int ASF::Tag::track() const {
|
|||
if (d->attributeListMap.contains("WM/Track"))
|
||||
return d->attributeListMap["WM/Track"][0].toUInt();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
String ASF::Tag::genre() const {
|
||||
|
||||
if (d->attributeListMap.contains("WM/Genre"))
|
||||
return d->attributeListMap["WM/Genre"][0].toString();
|
||||
return String();
|
||||
|
||||
}
|
||||
|
||||
void ASF::Tag::setTitle(const String &value) {
|
||||
|
@ -133,11 +140,7 @@ void ASF::Tag::setTrack(unsigned int value) {
|
|||
setAttribute("WM/TrackNumber", String::number(value));
|
||||
}
|
||||
|
||||
ASF::AttributeListMap &ASF::Tag::attributeListMap() {
|
||||
return d->attributeListMap;
|
||||
}
|
||||
|
||||
const ASF::AttributeListMap &ASF::Tag::attributeListMap() const {
|
||||
const ASF::AttributeListMap ASF::Tag::attributeListMap() const {
|
||||
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) {
|
||||
|
||||
AttributeList value;
|
||||
value.append(attribute);
|
||||
d->attributeListMap.insert(name, value);
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (d->attributeListMap.contains(name)) {
|
||||
d->attributeListMap[name].append(attribute);
|
||||
}
|
||||
else {
|
||||
setAttribute(name, attribute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ASF::Tag::isEmpty() const {
|
||||
|
||||
return Strawberry_TagLib::TagLib::Tag::isEmpty() &&
|
||||
copyright().isEmpty() &&
|
||||
rating().isEmpty() &&
|
||||
d->attributeListMap.isEmpty();
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -224,16 +233,19 @@ const char *keyTranslation[][2] = {
|
|||
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||
|
||||
String translateKey(const String &key) {
|
||||
|
||||
for (size_t i = 0; i < keyTranslationSize; ++i) {
|
||||
if (key == keyTranslation[i][0])
|
||||
return keyTranslation[i][1];
|
||||
}
|
||||
|
||||
return String();
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
PropertyMap ASF::Tag::properties() const {
|
||||
|
||||
PropertyMap props;
|
||||
|
||||
if (!d->title.isEmpty()) {
|
||||
|
@ -271,15 +283,19 @@ PropertyMap ASF::Tag::properties() const {
|
|||
}
|
||||
}
|
||||
return props;
|
||||
|
||||
}
|
||||
|
||||
void ASF::Tag::removeUnsupportedProperties(const StringList &props) {
|
||||
|
||||
StringList::ConstIterator it = props.begin();
|
||||
for (; it != props.end(); ++it)
|
||||
d->attributeListMap.erase(*it);
|
||||
|
||||
}
|
||||
|
||||
PropertyMap ASF::Tag::setProperties(const PropertyMap &props) {
|
||||
|
||||
static Map<String, String> reverseKeyMap;
|
||||
if (reverseKeyMap.isEmpty()) {
|
||||
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||
|
@ -339,4 +355,5 @@ PropertyMap ASF::Tag::setProperties(const PropertyMap &props) {
|
|||
}
|
||||
|
||||
return ignoredProps;
|
||||
|
||||
}
|
||||
|
|
|
@ -50,150 +50,135 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
|||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Returns the track name.
|
||||
*/
|
||||
* Returns the track name.
|
||||
*/
|
||||
virtual String title() const;
|
||||
|
||||
/*!
|
||||
* Returns the artist name.
|
||||
*/
|
||||
* Returns the artist name.
|
||||
*/
|
||||
virtual String artist() const;
|
||||
|
||||
/*!
|
||||
* Returns the album name; if no album name is present in the tag
|
||||
* String::null will be returned.
|
||||
*/
|
||||
* Returns the album name; if no album name is present in the tag String::null will be returned.
|
||||
*/
|
||||
virtual String album() const;
|
||||
|
||||
/*!
|
||||
* Returns the track comment.
|
||||
*/
|
||||
* Returns the track comment.
|
||||
*/
|
||||
virtual String comment() const;
|
||||
|
||||
/*!
|
||||
* Returns the genre name; if no genre is present in the tag String::null
|
||||
* will be returned.
|
||||
*/
|
||||
* Returns the genre name; if no genre is present in the tag String::null will be returned.
|
||||
*/
|
||||
virtual String genre() const;
|
||||
|
||||
/*!
|
||||
* Returns the rating.
|
||||
*/
|
||||
* Returns the rating.
|
||||
*/
|
||||
virtual String rating() const;
|
||||
|
||||
/*!
|
||||
* Returns the genre name; if no genre is present in the tag String::null
|
||||
* will be returned.
|
||||
*/
|
||||
* Returns the genre name; if no genre is present in the tag String::null will be returned.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the track number; if there is no track number set, this will
|
||||
* return 0.
|
||||
*/
|
||||
* Returns the track number; if there is no track number set, this will return 0.
|
||||
*/
|
||||
virtual unsigned int track() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a s.
|
||||
*/
|
||||
* Sets the title to \a 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);
|
||||
|
||||
/*!
|
||||
* Sets the album to \a s. If \a s is String::null then this value will be
|
||||
* cleared.
|
||||
*/
|
||||
* Sets the album to \a s. If \a s is String::null then this value will be cleared.
|
||||
*/
|
||||
virtual void setAlbum(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the comment to \a s.
|
||||
*/
|
||||
* Sets the comment to \a 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);
|
||||
|
||||
/*!
|
||||
* Sets the copyright to \a s.
|
||||
*/
|
||||
* Sets the copyright to \a 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns true if the tag does not contain any data. This should be
|
||||
* reimplemented in subclasses that provide more than the basic tagging
|
||||
* abilities in this class.
|
||||
*/
|
||||
* Returns true if the tag does not contain any data.
|
||||
* This should be reimplemented in subclasses that provide more than the basic tagging abilities in this class.
|
||||
*/
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
*/
|
||||
AttributeListMap &attributeListMap();
|
||||
* Returns a reference to the item list map. This is an AttributeListMap of all of the items in the tag.
|
||||
*/
|
||||
const AttributeListMap attributeListMap() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the item list map. This is an AttributeListMap of
|
||||
* 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.
|
||||
*/
|
||||
* \return True if a value for \a attribute is currently set.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* \return The list of values for the key \a name, or an empty list if no
|
||||
* values have been set.
|
||||
*/
|
||||
* \return The list of values for the key \a name, or an empty list if no values have been set.
|
||||
*/
|
||||
AttributeList attribute(const String &name) const;
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
void addAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
PropertyMap properties() const;
|
||||
|
|
|
@ -89,8 +89,7 @@ class AudioProperties::AudioPropertiesPrivate {
|
|||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AudioProperties::~AudioProperties() {
|
||||
}
|
||||
AudioProperties::~AudioProperties() {}
|
||||
|
||||
int AudioProperties::lengthInSeconds() const {
|
||||
VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0)
|
||||
|
@ -104,5 +103,4 @@ int AudioProperties::lengthInMilliseconds() const {
|
|||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AudioProperties::AudioProperties(ReadStyle) : d(0) {
|
||||
}
|
||||
AudioProperties::AudioProperties(ReadStyle) : d(nullptr) {}
|
||||
|
|
|
@ -34,21 +34,20 @@ namespace TagLib {
|
|||
//! A simple, abstract interface to common audio properties
|
||||
|
||||
/*!
|
||||
* The values here are common to most audio formats. For more specific, codec
|
||||
* dependent values, please see see the subclasses APIs. This is meant to
|
||||
* compliment the TagLib::File and TagLib::Tag APIs in providing a simple
|
||||
* The values here are common to most audio formats.
|
||||
* For more specific, codec dependent values, please see see the subclasses APIs.
|
||||
* This is meant to compliment the TagLib::File and TagLib::Tag APIs in providing a simple
|
||||
* interface that is sufficient for most applications.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT AudioProperties {
|
||||
public:
|
||||
/*!
|
||||
* Reading audio properties from a file can sometimes be very time consuming
|
||||
* and for the most accurate results can often involve reading the entire
|
||||
* file. Because in many situations speed is critical or the accuracy of the
|
||||
* values is not particularly important this allows the level of desired
|
||||
* accuracy to be set.
|
||||
*/
|
||||
* Reading audio properties from a file can sometimes be very time consuming
|
||||
* and for the most accurate results can often involve reading the entire file.
|
||||
* Because in many situations speed is critical or the accuracy of the values
|
||||
* is not particularly important this allows the level of desired accuracy to be set.
|
||||
*/
|
||||
enum ReadStyle {
|
||||
//! Read as little of the file as possible
|
||||
Fast,
|
||||
|
@ -59,57 +58,55 @@ class TAGLIB_EXPORT AudioProperties {
|
|||
};
|
||||
|
||||
/*!
|
||||
* Destroys this AudioProperties instance.
|
||||
*/
|
||||
* Destroys this AudioProperties instance.
|
||||
*/
|
||||
virtual ~AudioProperties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds.
|
||||
*/
|
||||
virtual int length() const = 0;
|
||||
* Returns the length of the file in seconds.
|
||||
*/
|
||||
//virtual int length() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInSeconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInMilliseconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the most appropriate bit rate for the file in kb/s. For constant
|
||||
* bitrate formats this is simply the bitrate of the file. For variable
|
||||
* bitrate formats this is either the average or nominal bitrate.
|
||||
*/
|
||||
* Returns the most appropriate bit rate for the file in kb/s. For constant bitrate formats this is simply the bitrate of the file.
|
||||
* For variable bitrate formats this is either the average or nominal bitrate.
|
||||
*/
|
||||
virtual int bitrate() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const = 0;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Construct an audio properties instance. This is protected as this class
|
||||
* should not be instantiated directly, but should be instantiated via its
|
||||
* subclasses and can be fetched from the FileRef or File APIs.
|
||||
*
|
||||
* \see ReadStyle
|
||||
*/
|
||||
* Construct an audio properties instance.
|
||||
* This is protected as this class should not be instantiated directly,
|
||||
* but should be instantiated via its subclasses and can be fetched from the FileRef or File APIs.
|
||||
*
|
||||
* \see ReadStyle
|
||||
*/
|
||||
AudioProperties(ReadStyle style);
|
||||
|
||||
private:
|
||||
|
|
|
@ -76,42 +76,44 @@ unsigned int DSDIFF::DIIN::Tag::track() const {
|
|||
}
|
||||
|
||||
void DSDIFF::DIIN::Tag::setTitle(const String &title) {
|
||||
|
||||
if (title.isNull() || title.isEmpty())
|
||||
d->title = String();
|
||||
else
|
||||
d->title = title;
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::DIIN::Tag::setArtist(const String &artist) {
|
||||
|
||||
if (artist.isNull() || artist.isEmpty())
|
||||
d->artist = String();
|
||||
else
|
||||
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 properties;
|
||||
properties["TITLE"] = d->title;
|
||||
properties["ARTIST"] = d->artist;
|
||||
return properties;
|
||||
|
||||
}
|
||||
|
||||
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps) {
|
||||
|
||||
PropertyMap properties(origProps);
|
||||
properties.removeEmpty();
|
||||
StringList oneValueSet;
|
||||
|
@ -140,4 +142,5 @@ PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps) {
|
|||
}
|
||||
|
||||
return properties;
|
||||
|
||||
}
|
||||
|
|
|
@ -30,109 +30,103 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace DSDIFF {
|
||||
|
||||
namespace DIIN {
|
||||
|
||||
/*!
|
||||
* Tags from the Edited Master Chunk Info
|
||||
*
|
||||
* Only Title and Artist tags are supported
|
||||
*/
|
||||
* Tags from the Edited Master Chunk Info
|
||||
*
|
||||
* Only Title and Artist tags are supported
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
||||
public:
|
||||
Tag();
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Returns the track name; if no track name is present in the tag
|
||||
* String() will be returned.
|
||||
*/
|
||||
* Returns the track name; if no track name is present in the tag String() will be returned.
|
||||
*/
|
||||
String title() const;
|
||||
|
||||
/*!
|
||||
* Returns the artist name; if no artist name is present in the tag
|
||||
* String() will be returned.
|
||||
*/
|
||||
* Returns the artist name; if no artist name is present in the tag String() will be returned.
|
||||
*/
|
||||
String artist() const;
|
||||
|
||||
/*!
|
||||
* Not supported. Therefore always returns String().
|
||||
*/
|
||||
* Not supported. Therefore always returns String().
|
||||
*/
|
||||
String album() const;
|
||||
|
||||
/*!
|
||||
* Not supported. Therefore always returns String().
|
||||
*/
|
||||
* Not supported. Therefore always returns String().
|
||||
*/
|
||||
String comment() const;
|
||||
|
||||
/*!
|
||||
* Not supported. Therefore always returns String().
|
||||
*/
|
||||
* Not supported. Therefore always returns String().
|
||||
*/
|
||||
String genre() const;
|
||||
|
||||
/*!
|
||||
* Not supported. Therefore always returns 0.
|
||||
*/
|
||||
* Not supported. Therefore always returns 0.
|
||||
*/
|
||||
unsigned int year() const;
|
||||
|
||||
/*!
|
||||
* Not supported. Therefore always returns 0.
|
||||
*/
|
||||
* Not supported. Therefore always returns 0.
|
||||
*/
|
||||
unsigned int track() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a title. If \a title is String() then this
|
||||
* value will be cleared.
|
||||
*/
|
||||
* Sets the title to \a title. If \a title is String() then this value will be cleared.
|
||||
*/
|
||||
void setTitle(const String &title);
|
||||
|
||||
/*!
|
||||
* Sets the artist to \a artist. If \a artist is String() then this
|
||||
* value will be cleared.
|
||||
*/
|
||||
* Sets the artist to \a artist. If \a artist is String() then this value will be cleared.
|
||||
*/
|
||||
void setArtist(const String &artist);
|
||||
|
||||
/*!
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
void setAlbum(const String &album);
|
||||
|
||||
/*!
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
void setComment(const String &comment);
|
||||
|
||||
/*!
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
void setGenre(const String &genre);
|
||||
|
||||
/*!
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
void setYear(unsigned int year);
|
||||
|
||||
/*!
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
* Not supported and therefore ignored.
|
||||
*/
|
||||
void setTrack(unsigned int track);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* Since the DIIN tag is very limited, the exported map is as well.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* Since the DIIN tag is very limited, the exported map is as well.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Because of the limitations of the DIIN file tag, any tags besides
|
||||
* TITLE and ARTIST, will be
|
||||
* returned. Additionally, if the map contains tags with multiple values,
|
||||
* all but the first will be contained in the returned map of unsupported
|
||||
* properties.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* Because of the limitations of the DIIN file tag, any tags besides
|
||||
* TITLE and ARTIST, will be 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 &);
|
||||
|
||||
private:
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tbytevector.h>
|
||||
#include <tdebug.h>
|
||||
#include <id3v2tag.h>
|
||||
|
@ -48,15 +49,18 @@ struct Chunk64 {
|
|||
typedef std::vector<Chunk64> ChunkList;
|
||||
|
||||
int chunkIndex(const ChunkList &chunks, const ByteVector &id) {
|
||||
|
||||
for (unsigned long int i = 0; i < chunks.size(); i++) {
|
||||
if (chunks[i].name == id)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
bool isValidChunkID(const ByteVector &name) {
|
||||
|
||||
if (name.size() != 4)
|
||||
return false;
|
||||
|
||||
|
@ -66,6 +70,7 @@ bool isValidChunkID(const ByteVector &name) {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
enum {
|
||||
|
@ -84,7 +89,7 @@ class DSDIFF::File::FilePrivate {
|
|||
size(0),
|
||||
isID3InPropChunk(false),
|
||||
duplicateID3V2chunkIndex(-1),
|
||||
properties(0),
|
||||
properties(nullptr),
|
||||
id3v2TagChunkID("ID3 "),
|
||||
hasID3v2(false),
|
||||
hasDiin(false) {
|
||||
|
@ -128,30 +133,34 @@ class DSDIFF::File::FilePrivate {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool DSDIFF::File::isSupported(IOStream *stream) {
|
||||
|
||||
// A DSDIFF file has to start with "FRM8????????DSD ".
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 16, false);
|
||||
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DSDIFF::File::File(FileName file, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file) {
|
||||
DSDIFF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file) {
|
||||
|
||||
d = new FilePrivate;
|
||||
d->endianness = BigEndian;
|
||||
if (isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
|
||||
}
|
||||
|
||||
DSDIFF::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream) {
|
||||
DSDIFF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream) {
|
||||
|
||||
d = new FilePrivate;
|
||||
d->endianness = BigEndian;
|
||||
if (isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
|
||||
}
|
||||
|
||||
DSDIFF::File::~File() {
|
||||
|
@ -179,18 +188,22 @@ bool DSDIFF::File::hasDIINTag() const {
|
|||
}
|
||||
|
||||
PropertyMap DSDIFF::File::properties() const {
|
||||
|
||||
if (d->hasID3v2)
|
||||
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
|
||||
|
||||
return PropertyMap();
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported) {
|
||||
|
||||
if (d->hasID3v2)
|
||||
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported);
|
||||
|
||||
if (d->hasDiin)
|
||||
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported);
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("DSDIFF::File::save() -- File is read only.");
|
||||
return false;
|
||||
|
@ -279,9 +293,11 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::strip(TagTypes tags) {
|
||||
|
||||
if (tags & ID3v2) {
|
||||
removeRootChunk("ID3 ");
|
||||
removeRootChunk("id3 ");
|
||||
|
@ -296,6 +312,7 @@ void DSDIFF::File::strip(TagTypes tags) {
|
|||
d->hasDiin = false;
|
||||
d->tag.set(DIINIndex, new DIIN::Tag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -303,6 +320,7 @@ void DSDIFF::File::strip(TagTypes tags) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DSDIFF::File::removeRootChunk(unsigned int i) {
|
||||
|
||||
unsigned long long chunkSize = d->chunks[i].size + d->chunks[i].padding + 12;
|
||||
|
||||
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.erase(d->chunks.begin() + i);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::removeRootChunk(const ByteVector &id) {
|
||||
|
||||
int i = chunkIndex(d->chunks, id);
|
||||
|
||||
if (i >= 0)
|
||||
removeRootChunk(i);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data) {
|
||||
|
||||
if (data.isEmpty()) {
|
||||
removeRootChunk(i);
|
||||
return;
|
||||
|
@ -350,9 +372,11 @@ void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data) {
|
|||
// Finally update the internal offsets
|
||||
|
||||
updateRootChunksStructure(i + 1);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data) {
|
||||
|
||||
if (d->chunks.size() == 0) {
|
||||
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
|
||||
return;
|
||||
|
@ -387,9 +411,11 @@ void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &da
|
|||
chunk.padding = (data.size() & 0x01) ? 1 : 0;
|
||||
|
||||
d->chunks.push_back(chunk);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum) {
|
||||
|
||||
ChunkList &childChunks = d->childChunks[childChunkNum];
|
||||
|
||||
// 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;
|
||||
|
||||
childChunks.erase(childChunks.begin() + i);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::setChildChunkData(unsigned int i,
|
||||
const ByteVector &data,
|
||||
unsigned int childChunkNum) {
|
||||
void DSDIFF::File::setChildChunkData(unsigned int i, const ByteVector &data, unsigned int childChunkNum) {
|
||||
|
||||
ChunkList &childChunks = d->childChunks[childChunkNum];
|
||||
|
||||
if (data.isEmpty()) {
|
||||
|
@ -445,11 +471,8 @@ void DSDIFF::File::setChildChunkData(unsigned int i,
|
|||
|
||||
// And the PROP chunk size
|
||||
|
||||
d->chunks[d->childChunkIndex[childChunkNum]].size +=
|
||||
((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);
|
||||
d->chunks[d->childChunkIndex[childChunkNum]].size += ((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);
|
||||
|
||||
// Now update the specific chunk
|
||||
|
||||
|
@ -468,11 +491,11 @@ void DSDIFF::File::setChildChunkData(unsigned int i,
|
|||
|
||||
// And for root chunks
|
||||
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::setChildChunkData(const ByteVector &name,
|
||||
const ByteVector &data,
|
||||
unsigned int childChunkNum) {
|
||||
void DSDIFF::File::setChildChunkData(const ByteVector &name, const ByteVector &data, unsigned int childChunkNum) {
|
||||
|
||||
ChunkList &childChunks = d->childChunks[childChunkNum];
|
||||
|
||||
if (childChunks.size() == 0) {
|
||||
|
@ -530,9 +553,11 @@ void DSDIFF::File::setChildChunkData(const ByteVector &name,
|
|||
chunk.padding = (data.size() & 0x01) ? 1 : 0;
|
||||
|
||||
childChunks.push_back(chunk);
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk) {
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) {
|
||||
|
||||
bool bigEndian = (d->endianness == BigEndian);
|
||||
|
||||
d->type = readBlock(4);
|
||||
|
@ -856,11 +883,11 @@ void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesSty
|
|||
d->isID3InPropChunk = false;
|
||||
d->hasID3v2 = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
|
||||
unsigned long long offset, unsigned long replace,
|
||||
unsigned int leadingPadding) {
|
||||
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, unsigned long long offset, unsigned long replace, unsigned int leadingPadding) {
|
||||
|
||||
ByteVector combined;
|
||||
if (leadingPadding)
|
||||
combined.append(ByteVector(leadingPadding, '\x00'));
|
||||
|
@ -872,4 +899,5 @@ void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
|
|||
combined.append('\x00');
|
||||
|
||||
insert(combined, offset, replace);
|
||||
|
||||
}
|
||||
|
|
|
@ -37,34 +37,32 @@ namespace TagLib {
|
|||
//! An implementation of DSDIFF metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of DSDIFF metadata.
|
||||
*
|
||||
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
|
||||
* chunk as well as properties from the file.
|
||||
* Description of the DSDIFF format is available
|
||||
* at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
|
||||
* DSDIFF standard does not explicitly specify the ID3V2 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
|
||||
*/
|
||||
* This is implementation of DSDIFF metadata.
|
||||
*
|
||||
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
|
||||
* chunk as well as properties from the file.
|
||||
* Description of the DSDIFF format is available at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
|
||||
* DSDIFF standard does not explicitly specify the ID3V2 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
|
||||
*/
|
||||
|
||||
namespace DSDIFF {
|
||||
|
||||
//! An implementation of TagLib::File with DSDIFF specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for DSDIFF 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 DSDIFF files.
|
||||
*/
|
||||
* This implements and provides an interface for DSDIFF 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 DSDIFF files.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
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
|
||||
* the file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
* Constructs an DSDIFF file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an DSDIFF file from \a stream. 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
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs an DSDIFF file from \a stream.
|
||||
* 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 responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN
|
||||
* tags. The ID3v2 tag is given priority in reading the information -- if
|
||||
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
|
||||
* 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.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
* \see DIINTag()
|
||||
*/
|
||||
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN tags.
|
||||
* The ID3v2 tag is given priority in reading the information -- if requested information exists in both the ID3v2 tag and the ID3v1 tag,
|
||||
* 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.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
* \see DIINTag()
|
||||
*/
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the ID3V2 Tag for this file.
|
||||
*
|
||||
* \note This always returns a valid pointer regardless of whether or not
|
||||
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the
|
||||
* file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see hasID3v2Tag()
|
||||
*/
|
||||
* Returns the ID3V2 Tag for this file.
|
||||
*
|
||||
* \note This always returns a valid pointer regardless of whether or not the file on disk has an ID3v2 tag.
|
||||
* Use hasID3v2Tag() to check if the file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see hasID3v2Tag()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::properties().
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::properties().
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::setProperties().
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::setProperties().
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the AIFF::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the AIFF::Properties for this file.
|
||||
* If no audio properties were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this
|
||||
* will duplicate its content into the other tag. This returns true
|
||||
* if saving was successful.
|
||||
*
|
||||
* 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);
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this will duplicate its content into the other tag.
|
||||
* This returns true if saving was successful.
|
||||
*
|
||||
* 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);
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Save the file. If \a strip is specified, it is possible to choose if
|
||||
* tags not specified in \a tags should be stripped from the file or
|
||||
* retained. With \a version, it is possible to specify whether ID3v2.4
|
||||
* or ID3v2.3 should be used.
|
||||
*/
|
||||
* Save the file. If \a strip is specified,
|
||||
* it is possible to choose if tags not specified in \a tags should be stripped from the file or retained.
|
||||
* With \a version, it is possible to specify whether ID3v2.4 or ID3v2.3 should be used.
|
||||
*/
|
||||
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
|
||||
* file. By default it strips all tags. It returns true if the tags are
|
||||
* successfully stripped.
|
||||
*
|
||||
* \note This will update the file immediately.
|
||||
*/
|
||||
* This will strip the tags that match the OR-ed together TagTypes from the file.
|
||||
* By default it strips all tags. It returns true if the tags are successfully stripped.
|
||||
*
|
||||
* \note This will update the file immediately.
|
||||
*/
|
||||
void strip(TagTypes tags = AllTags);
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
*/
|
||||
bool hasID3v2Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has the DSDIFF
|
||||
* title and artist tags.
|
||||
*
|
||||
* \see DIINTag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has the DSDIFF title and artist tags.
|
||||
*
|
||||
* \see DIINTag()
|
||||
*/
|
||||
bool hasDIINTag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as a DSDIFF
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as a DSDIFF file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
protected:
|
||||
enum Endianness { BigEndian,
|
||||
LittleEndian };
|
||||
enum Endianness {
|
||||
BigEndian,
|
||||
LittleEndian
|
||||
};
|
||||
|
||||
File(FileName file, 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);
|
||||
|
||||
/*!
|
||||
* Sets the data for the the specified chunk at root level to \a data.
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
* Sets the data for the the specified chunk at root level to \a data.
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
void setRootChunkData(unsigned int i, const ByteVector &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
|
||||
* it will be overwritten, otherwise it will be
|
||||
* created after the existing chunks.
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
* Sets the data for the root-level chunk \a name to \a data.
|
||||
* If a root-level chunk with the given name already exists it will be overwritten, otherwise it will be created after the existing chunks.
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
void setRootChunkData(const ByteVector &name, const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Sets the data for the the specified child chunk to \a data.
|
||||
*
|
||||
* If data is null, then remove the chunk
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
void setChildChunkData(unsigned int i, const ByteVector &data,
|
||||
unsigned int childChunkNum);
|
||||
* Sets the data for the the specified child chunk to \a data.
|
||||
*
|
||||
* If data is null, then remove the chunk
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
void setChildChunkData(unsigned int i, const ByteVector &data, unsigned int childChunkNum);
|
||||
|
||||
/*!
|
||||
* Sets the data for the child chunk \a name to \a data. 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.
|
||||
*
|
||||
* If data is null, then remove the chunks with \a name name
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
* Sets the data for the child chunk \a name to \a data.
|
||||
* 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.
|
||||
*
|
||||
* If data is null, then remove the chunks with \a name name
|
||||
*
|
||||
* \warning This will update the file immediately.
|
||||
*/
|
||||
void setChildChunkData(const ByteVector &name, const ByteVector &data,
|
||||
unsigned int childChunkNum);
|
||||
|
||||
void updateRootChunksStructure(unsigned int startingChunk);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
void writeChunk(const ByteVector &name, const ByteVector &data,
|
||||
unsigned long long offset, unsigned long replace = 0,
|
||||
unsigned int leadingPadding = 0);
|
||||
void writeChunk(const ByteVector &name, const ByteVector &data, unsigned long long offset, unsigned long replace = 0, unsigned int leadingPadding = 0);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
|
|
|
@ -52,11 +52,8 @@ class DSDIFF::Properties::PropertiesPrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DSDIFF::Properties::Properties(const unsigned int sampleRate,
|
||||
const unsigned short channels,
|
||||
const unsigned long long samplesCount,
|
||||
const int bitrate,
|
||||
ReadStyle style) : AudioProperties(style) {
|
||||
DSDIFF::Properties::Properties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle style) : AudioProperties(style) {
|
||||
|
||||
d = new PropertiesPrivate;
|
||||
|
||||
d->channels = channels;
|
||||
|
@ -65,6 +62,7 @@ DSDIFF::Properties::Properties(const unsigned int sampleRate,
|
|||
d->sampleRate = sampleRate;
|
||||
d->bitrate = bitrate;
|
||||
d->length = d->sampleRate > 0 ? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5) : 0;
|
||||
|
||||
}
|
||||
|
||||
DSDIFF::Properties::~Properties() {
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace DSDIFF {
|
||||
|
||||
class File;
|
||||
|
@ -38,23 +37,19 @@ class File;
|
|||
//! An implementation of audio property reading for DSDIFF
|
||||
|
||||
/*!
|
||||
* This reads the data from an DSDIFF stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
* This reads the data from an DSDIFF stream found in the AudioProperties API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperties {
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of DSDIFF::Properties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*/
|
||||
Properties(const unsigned int sampleRate, const unsigned short channels,
|
||||
const unsigned long long samplesCount, const int bitrate,
|
||||
ReadStyle style);
|
||||
* Create an instance of DSDIFF::Properties with the data read from the ByteVector \a data.
|
||||
*/
|
||||
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();
|
||||
|
||||
// Reimplementations.
|
||||
|
@ -76,6 +71,7 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
|
|||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace DSDIFF
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -60,9 +60,11 @@ class DSF::File::FilePrivate {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool DSF::File::isSupported(IOStream *stream) {
|
||||
|
||||
// A DSF file has to start with "DSD "
|
||||
const ByteVector id = Utils::readHeader(stream, 4, false);
|
||||
return id.startsWith("DSD ");
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -70,17 +72,18 @@ bool DSF::File::isSupported(IOStream *stream) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DSF::File::File(FileName file, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file),
|
||||
d(new FilePrivate()) {
|
||||
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
|
||||
}
|
||||
|
||||
DSF::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream),
|
||||
d(new FilePrivate()) {
|
||||
DSF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties, propertiesStyle);
|
||||
|
||||
}
|
||||
|
||||
DSF::File::~File() {
|
||||
|
@ -104,6 +107,7 @@ DSF::Properties *DSF::File::audioProperties() const {
|
|||
}
|
||||
|
||||
bool DSF::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("DSF::File::save() -- File is read only.");
|
||||
return false;
|
||||
|
@ -158,6 +162,7 @@ bool DSF::File::save() {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -166,6 +171,7 @@ bool DSF::File::save() {
|
|||
|
||||
|
||||
void DSF::File::read(bool, Properties::ReadStyle propertiesStyle) {
|
||||
|
||||
// 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
|
||||
|
||||
|
@ -223,4 +229,5 @@ void DSF::File::read(bool, Properties::ReadStyle propertiesStyle) {
|
|||
d->tag = new ID3v2::Tag();
|
||||
else
|
||||
d->tag = new ID3v2::Tag(this, d->metadataOffset);
|
||||
|
||||
}
|
||||
|
|
|
@ -36,80 +36,79 @@ namespace TagLib {
|
|||
//! An implementation of DSF metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of DSF metadata.
|
||||
*
|
||||
* This supports an ID3v2 tag as well as properties from the file.
|
||||
*/
|
||||
* This is implementation of DSF metadata.
|
||||
*
|
||||
* This supports an ID3v2 tag as well as properties from the file.
|
||||
*/
|
||||
|
||||
namespace DSF {
|
||||
|
||||
//! An implementation of Strawberry_TagLib::TagLib::File with DSF specific methods
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* the abstract Strawberry_TagLib::TagLib::File API as well as providing some additional
|
||||
* information specific to DSF files.
|
||||
*/
|
||||
* 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
|
||||
* the abstract Strawberry_TagLib::TagLib::File API as well as providing some additional information specific to DSF files.
|
||||
*
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* Constructs an DSF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs an DSF file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read using \a propertiesStyle.
|
||||
* If false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an DSF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs an DSF file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read using \a propertiesStyle.
|
||||
* If false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file.
|
||||
*/
|
||||
* Returns the Tag for this file.
|
||||
*/
|
||||
ID3v2::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::properties().
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::properties().
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::setProperties().
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::setProperties().
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the DSF::AudioProperties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the DSF::AudioProperties for this file.
|
||||
* If no audio properties were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the file.
|
||||
*/
|
||||
* Saves the file.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as a DSF
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as a DSF file.
|
||||
*
|
||||
* \note This method is designed to do a quick check.
|
||||
* The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace DSF {
|
||||
|
||||
class File;
|
||||
|
@ -38,21 +37,19 @@ class File;
|
|||
//! An implementation of audio property reading for DSF
|
||||
|
||||
/*!
|
||||
* This reads the data from a DSF stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
* This reads the data from a DSF stream found in the AudioProperties API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperties {
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of DSF::AudioProperties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*/
|
||||
* Create an instance of DSF::AudioProperties with the data read from the ByteVector \a data.
|
||||
*/
|
||||
Properties(const ByteVector &data, ReadStyle style);
|
||||
|
||||
/*!
|
||||
* Destroys this DSF::AudioProperties instance.
|
||||
*/
|
||||
* Destroys this DSF::AudioProperties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
|
@ -68,9 +65,15 @@ class TAGLIB_EXPORT Properties : public Strawberry_TagLib::TagLib::AudioProperti
|
|||
int formatID() const;
|
||||
|
||||
/*!
|
||||
* Channel type values: 1 = mono, 2 = stereo, 3 = 3 channels,
|
||||
* 4 = quad, 5 = 4 channels, 6 = 5 channels, 7 = 5.1 channels
|
||||
*/
|
||||
* Channel type values:
|
||||
* 1 = mono,
|
||||
* 2 = stereo,
|
||||
* 3 = 3 channels,
|
||||
* 4 = quad,
|
||||
* 5 = 4 channels,
|
||||
* 6 = 5 channels,
|
||||
* 7 = 5.1 channels
|
||||
*/
|
||||
int channelType() const;
|
||||
int bitsPerSample() const;
|
||||
long long sampleCount() const;
|
||||
|
|
|
@ -63,8 +63,8 @@ ResolverList fileTypeResolvers;
|
|||
|
||||
// Detect the file type by user-defined resolvers.
|
||||
|
||||
File *detectByResolvers(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
File *detectByResolvers(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
|
||||
ResolverList::ConstIterator it = fileTypeResolvers.begin();
|
||||
for (; it != fileTypeResolvers.end(); ++it) {
|
||||
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
|
@ -73,12 +73,13 @@ File *detectByResolvers(FileName fileName, bool readAudioProperties,
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
// Detect the file type based on the file extension.
|
||||
|
||||
File *detectByExtension(IOStream *stream, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
File *detectByExtension(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
|
||||
#ifdef _WIN32
|
||||
const String s = stream->name().toString();
|
||||
#else
|
||||
|
@ -140,13 +141,14 @@ File *detectByExtension(IOStream *stream, bool readAudioProperties,
|
|||
return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
// Detect the file type based on the actual content of the stream.
|
||||
|
||||
File *detectByContent(IOStream *stream, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
File *file = 0;
|
||||
File *detectByContent(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
|
||||
File *file = nullptr;
|
||||
|
||||
if (MPEG::File::isSupported(stream))
|
||||
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||
|
@ -191,17 +193,17 @@ File *detectByContent(IOStream *stream, bool readAudioProperties,
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
// Internal function that supports FileRef::create().
|
||||
// This looks redundant, but necessary in order not to change the previous
|
||||
// behavior of FileRef::create().
|
||||
|
||||
File *createInternal(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
File *createInternal(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
|
||||
File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if (file)
|
||||
return file;
|
||||
if (file) return file;
|
||||
|
||||
#ifdef _WIN32
|
||||
const String s = fileName.toString();
|
||||
|
@ -266,14 +268,13 @@ File *createInternal(FileName fileName, bool readAudioProperties,
|
|||
return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class FileRef::FileRefPrivate : public RefCounter {
|
||||
public:
|
||||
FileRefPrivate() : RefCounter(),
|
||||
file(0),
|
||||
stream(0) {}
|
||||
FileRefPrivate() : RefCounter(), file(nullptr), stream(nullptr) {}
|
||||
|
||||
~FileRefPrivate() {
|
||||
delete file;
|
||||
|
@ -288,11 +289,9 @@ class FileRef::FileRefPrivate : public RefCounter {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileRef::FileRef() : d(new FileRefPrivate()) {
|
||||
}
|
||||
FileRef::FileRef() : d(new FileRefPrivate()) {}
|
||||
|
||||
FileRef::FileRef(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) : d(new FileRefPrivate()) {
|
||||
FileRef::FileRef(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : d(new FileRefPrivate()) {
|
||||
parse(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
|
@ -309,24 +308,30 @@ FileRef::FileRef(const FileRef &ref) : d(ref.d) {
|
|||
}
|
||||
|
||||
FileRef::~FileRef() {
|
||||
|
||||
if (d->deref())
|
||||
delete d;
|
||||
|
||||
}
|
||||
|
||||
Tag *FileRef::tag() const {
|
||||
|
||||
if (isNull()) {
|
||||
debug("FileRef::tag() - Called without a valid file.");
|
||||
return nullptr;
|
||||
}
|
||||
return d->file->tag();
|
||||
|
||||
}
|
||||
|
||||
AudioProperties *FileRef::audioProperties() const {
|
||||
|
||||
if (isNull()) {
|
||||
debug("FileRef::audioProperties() - Called without a valid file.");
|
||||
return nullptr;
|
||||
}
|
||||
return d->file->audioProperties();
|
||||
|
||||
}
|
||||
|
||||
File *FileRef::file() const {
|
||||
|
@ -334,20 +339,22 @@ File *FileRef::file() const {
|
|||
}
|
||||
|
||||
bool FileRef::save() {
|
||||
|
||||
if (isNull()) {
|
||||
debug("FileRef::save() - Called without a valid file.");
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
StringList FileRef::defaultFileExtensions() {
|
||||
|
||||
StringList l;
|
||||
|
||||
l.append("ogg");
|
||||
|
@ -383,6 +390,7 @@ StringList FileRef::defaultFileExtensions() {
|
|||
l.append("dsdiff"); // alias for "dff"
|
||||
|
||||
return l;
|
||||
|
||||
}
|
||||
|
||||
bool FileRef::isNull() const {
|
||||
|
@ -408,9 +416,7 @@ bool FileRef::operator!=(const FileRef &ref) const {
|
|||
return (ref.d->file != d->file);
|
||||
}
|
||||
|
||||
File *FileRef::create(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) // static
|
||||
{
|
||||
File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { // static
|
||||
return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
|
@ -418,8 +424,8 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
|
|||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FileRef::parse(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
void FileRef::parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
|
||||
// Try user-defined resolvers.
|
||||
|
||||
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.
|
||||
|
||||
delete d->stream;
|
||||
d->stream = 0;
|
||||
d->stream = nullptr;
|
||||
|
||||
}
|
||||
|
||||
void FileRef::parse(IOStream *stream, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
void FileRef::parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) {
|
||||
|
||||
// User-defined resolvers won't work with a stream.
|
||||
|
||||
// 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.
|
||||
|
||||
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
}
|
||||
|
|
|
@ -40,18 +40,15 @@ class Tag;
|
|||
//! This class provides a simple abstraction for creating and handling files
|
||||
|
||||
/*!
|
||||
* FileRef exists to provide a minimal, generic and value-based wrapper around
|
||||
* a File. It is lightweight and implicitly shared, and as such suitable for
|
||||
* pass-by-value use. This hides some of the uglier details of TagLib::File
|
||||
* and the non-generic portions of the concrete file implementations.
|
||||
* FileRef exists to provide a minimal, generic and value-based wrapper around a File.
|
||||
* It is lightweight and implicitly shared, and as such suitable for pass-by-value use.
|
||||
* This hides some of the uglier details of TagLib::File and the non-generic portions of the concrete file implementations.
|
||||
*
|
||||
* 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
|
||||
* across file types.
|
||||
* to be able to get and set some of the tag information that is similar across file types.
|
||||
*
|
||||
* 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
|
||||
* the FileTypeResolver.
|
||||
* type system rather than using the constructor that accepts a file name using the FileTypeResolver.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
* \see addFileTypeResolver()
|
||||
|
@ -62,8 +59,7 @@ class TAGLIB_EXPORT FileRef {
|
|||
//! A class for pluggable file type resolution.
|
||||
|
||||
/*!
|
||||
* This class is used to add extend TagLib's very basic file name based file
|
||||
* type resolution.
|
||||
* This class is used to add extend TagLib's very basic file name based file type resolution.
|
||||
*
|
||||
* This can be accomplished with:
|
||||
*
|
||||
|
@ -83,191 +79,177 @@ class TAGLIB_EXPORT FileRef {
|
|||
*
|
||||
* \endcode
|
||||
*
|
||||
* Naturally a less contrived example would be slightly more complex. This
|
||||
* can be used to plug in mime-type detection systems or to add new file types
|
||||
* to TagLib.
|
||||
* Naturally a less contrived example would be slightly more complex.
|
||||
* This can be used to plug in mime-type detection systems or to add new file types to TagLib.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT FileTypeResolver {
|
||||
public:
|
||||
virtual ~FileTypeResolver();
|
||||
/*!
|
||||
* This method must be overridden to provide an additional file type
|
||||
* resolver. If the resolver is able to determine the file type it should
|
||||
* 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. Deletion will happen automatically when the FileRef passes
|
||||
* out of scope.
|
||||
*/
|
||||
* This method must be overridden to provide an additional file type resolver.
|
||||
* If the resolver is able to determine the file type it should 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.
|
||||
* Deletion will happen automatically when the FileRef passes out of scope.
|
||||
*/
|
||||
virtual File *createFile(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average) const = 0;
|
||||
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Creates a null FileRef.
|
||||
*/
|
||||
* Creates a null FileRef.
|
||||
*/
|
||||
FileRef();
|
||||
|
||||
/*!
|
||||
* Create a FileRef from \a fileName. 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
|
||||
* ignored.
|
||||
*
|
||||
* Also see the note in the class documentation about why you may not want to
|
||||
* use this method in your application.
|
||||
*/
|
||||
* Create a FileRef from \a fileName.
|
||||
* 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 ignored.
|
||||
*
|
||||
* Also see the note in the class documentation about why you may not want to
|
||||
* use this method in your application.
|
||||
*/
|
||||
explicit FileRef(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Construct a FileRef from an opened \a IOStream. 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
|
||||
* ignored.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
* Construct a FileRef from an opened \a IOStream.
|
||||
* 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 ignored.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
explicit FileRef(IOStream *stream,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Construct a FileRef using \a file. The FileRef now takes ownership of the
|
||||
* pointer and will delete the File when it passes out of scope.
|
||||
*/
|
||||
* Construct a FileRef using \a file.
|
||||
* The FileRef now takes ownership of the pointer and will delete the File when it passes out of scope.
|
||||
*/
|
||||
explicit FileRef(File *file);
|
||||
|
||||
/*!
|
||||
* Make a copy of \a ref.
|
||||
*/
|
||||
* Make a copy of \a ref.
|
||||
*/
|
||||
FileRef(const FileRef &ref);
|
||||
|
||||
/*!
|
||||
* Destroys this FileRef instance.
|
||||
*/
|
||||
* Destroys this FileRef instance.
|
||||
*/
|
||||
virtual ~FileRef();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to represented file's tag.
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*
|
||||
* \warning Do not cast it to any subclasses of \class Tag.
|
||||
* Use tag returning methods of appropriate subclasses of \class File instead.
|
||||
*
|
||||
* \see File::tag()
|
||||
*/
|
||||
* Returns a pointer to represented file's tag.
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*
|
||||
* \warning Do not cast it to any subclasses of \class Tag.
|
||||
* Use tag returning methods of appropriate subclasses of \class File instead.
|
||||
*
|
||||
* \see File::tag()
|
||||
*/
|
||||
Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the audio properties for this FileRef. If no audio properties
|
||||
* were read then this will returns a null pointer.
|
||||
*/
|
||||
* Returns the audio properties for this FileRef.
|
||||
* If no audio properties were read then this will returns a null pointer.
|
||||
*/
|
||||
AudioProperties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* with file objects directly, you are probably better served instantiating
|
||||
* 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
|
||||
* wrapper around a File. Accessing the file directly generally indicates
|
||||
* a moving away from this simplicity (and into things beyond the scope of
|
||||
* FileRef).
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*/
|
||||
* 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
|
||||
* with file objects directly, you are probably better served instantiating
|
||||
* 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
|
||||
* wrapper around a File. Accessing the file directly generally indicates
|
||||
* a moving away from this simplicity (and into things beyond the scope of
|
||||
* FileRef).
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*/
|
||||
File *file() const;
|
||||
|
||||
/*!
|
||||
* Saves the file. Returns true on success.
|
||||
*/
|
||||
* Saves the file. Returns true on success.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
/*!
|
||||
* Adds a FileTypeResolver to the list of those used by TagLib. Each
|
||||
* additional FileTypeResolver is added to the front of a list of resolvers
|
||||
* that are tried. If the FileTypeResolver returns zero the next resolver
|
||||
* is tried.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
* Adds a FileTypeResolver to the list of those used by TagLib.
|
||||
* Each additional FileTypeResolver is added to the front of a list of resolvers that are tried.
|
||||
* If the FileTypeResolver returns zero the next resolver is tried.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
|
||||
|
||||
/*!
|
||||
* As is mentioned elsewhere in this class's documentation, the default file
|
||||
* type resolution code provided by TagLib only works by comparing file
|
||||
* extensions.
|
||||
*
|
||||
* This method returns the list of file extensions that are used by default.
|
||||
*
|
||||
* The extensions are all returned in lowercase, though the comparison used
|
||||
* by TagLib for resolution is case-insensitive.
|
||||
*
|
||||
* \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
|
||||
* mime-type resolution system, but is just here for reference.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
* As is mentioned elsewhere in this class's documentation, the default file
|
||||
* type resolution code provided by TagLib only works by comparing file extensions.
|
||||
*
|
||||
* This method returns the list of file extensions that are used by default.
|
||||
*
|
||||
* The extensions are all returned in lowercase, though the comparison used
|
||||
* by TagLib for resolution is case-insensitive.
|
||||
*
|
||||
* \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
|
||||
* mime-type resolution system, but is just here for reference.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* Returns true if this FileRef and \a ref do not point to the same File
|
||||
* object.
|
||||
*/
|
||||
* Returns true if this FileRef and \a ref do not point to the same File object.
|
||||
*/
|
||||
bool operator!=(const FileRef &ref) const;
|
||||
|
||||
/*!
|
||||
* A simple implementation of file type guessing. 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 ignored.
|
||||
*
|
||||
* \note You generally shouldn't use this method, but instead the constructor
|
||||
* directly.
|
||||
*
|
||||
* \deprecated
|
||||
*/
|
||||
* A simple implementation of file type guessing.
|
||||
* 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 ignored.
|
||||
*
|
||||
* \note You generally shouldn't use this method, but instead the constructor directly.
|
||||
*
|
||||
* \deprecated
|
||||
*/
|
||||
static File *create(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
|
||||
|
|
|
@ -64,7 +64,7 @@ class FLAC::File::FilePrivate {
|
|||
ID3v2Location(-1),
|
||||
ID3v2OriginalSize(0),
|
||||
ID3v1Location(-1),
|
||||
properties(0),
|
||||
properties(nullptr),
|
||||
flacStart(0),
|
||||
streamStart(0),
|
||||
scanned(false) {
|
||||
|
@ -97,34 +97,30 @@ class FLAC::File::FilePrivate {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool FLAC::File::isSupported(IOStream *stream) {
|
||||
|
||||
// A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede.
|
||||
|
||||
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
||||
return (buffer.find("fLaC") >= 0);
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
|
||||
d(new FilePrivate()) {
|
||||
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(frameFactory)) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
FLAC::File::File(FileName file, ID3v2::FrameFactory *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)) {
|
||||
|
||||
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
|
||||
d(new FilePrivate(frameFactory)) {
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
FLAC::File::~File() {
|
||||
|
@ -152,6 +148,7 @@ FLAC::Properties *FLAC::File::audioProperties() const {
|
|||
}
|
||||
|
||||
bool FLAC::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("FLAC::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
|
@ -288,6 +285,7 @@ bool FLAC::File::save() {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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<Picture *> pictures;
|
||||
for (BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
|
||||
Picture *picture = dynamic_cast<Picture *>(*it);
|
||||
|
@ -325,6 +310,7 @@ List<FLAC::Picture *> FLAC::File::pictureList() {
|
|||
}
|
||||
}
|
||||
return pictures;
|
||||
|
||||
}
|
||||
|
||||
void FLAC::File::addPicture(Picture *picture) {
|
||||
|
@ -332,15 +318,18 @@ void FLAC::File::addPicture(Picture *picture) {
|
|||
}
|
||||
|
||||
void FLAC::File::removePicture(Picture *picture, bool del) {
|
||||
|
||||
BlockIterator it = d->blocks.find(picture);
|
||||
if (it != d->blocks.end())
|
||||
d->blocks.erase(it);
|
||||
|
||||
if (del)
|
||||
delete picture;
|
||||
|
||||
}
|
||||
|
||||
void FLAC::File::removePictures() {
|
||||
|
||||
for (BlockIterator it = d->blocks.begin(); it != d->blocks.end();) {
|
||||
if (dynamic_cast<Picture *>(*it)) {
|
||||
delete *it;
|
||||
|
@ -350,19 +339,22 @@ void FLAC::File::removePictures() {
|
|||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FLAC::File::strip(int tags) {
|
||||
|
||||
if (tags & ID3v1)
|
||||
d->tag.set(FlacID3v1Index, 0);
|
||||
d->tag.set(FlacID3v1Index, nullptr);
|
||||
|
||||
if (tags & ID3v2)
|
||||
d->tag.set(FlacID3v2Index, 0);
|
||||
d->tag.set(FlacID3v2Index, nullptr);
|
||||
|
||||
if (tags & XiphComment) {
|
||||
xiphComment()->removeAllFields();
|
||||
xiphComment()->removeAllPictures();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool FLAC::File::hasXiphComment() const {
|
||||
|
@ -382,6 +374,7 @@ bool FLAC::File::hasID3v2Tag() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::File::read(bool readProperties) {
|
||||
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = Utils::findID3v2(this);
|
||||
|
@ -425,9 +418,11 @@ void FLAC::File::read(bool readProperties) {
|
|||
|
||||
d->properties = new Properties(infoData, streamLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FLAC::File::scan() {
|
||||
|
||||
// Scan the metadata pages
|
||||
|
||||
if (d->scanned)
|
||||
|
@ -494,7 +489,7 @@ void FLAC::File::scan() {
|
|||
return;
|
||||
}
|
||||
|
||||
MetadataBlock *block = 0;
|
||||
MetadataBlock *block = nullptr;
|
||||
|
||||
// Found the vorbis-comment
|
||||
if (blockType == MetadataBlock::VorbisComment) {
|
||||
|
@ -537,4 +532,5 @@ void FLAC::File::scan() {
|
|||
d->streamStart = nextBlockOffset;
|
||||
|
||||
d->scanned = true;
|
||||
|
||||
}
|
||||
|
|
|
@ -52,31 +52,30 @@ class XiphComment;
|
|||
//! An implementation of FLAC metadata
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* under the Ogg hierarchy.
|
||||
*
|
||||
* This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
|
||||
* properties from the file.
|
||||
*/
|
||||
* 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
|
||||
* under the Ogg hierarchy.
|
||||
*
|
||||
* This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
|
||||
* properties from the file.
|
||||
*/
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
//! An implementation of TagLib::File with FLAC specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for FLAC 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 FLAC files.
|
||||
*/
|
||||
* This implements and provides an interface for FLAC 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 FLAC files.
|
||||
*
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
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
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \deprecated This constructor will be dropped in favor of the one below
|
||||
* in a future version.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
* Constructs an FLAC file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using \a frameFactory.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs a FLAC file from \a stream. 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 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(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs a FLAC file from \a stream. 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
|
||||
* 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.
|
||||
*/
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be a union of XiphComment,
|
||||
* ID3v1 and ID3v2 tags.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
* \see ID3v1Tag()
|
||||
* \see XiphComment()
|
||||
*/
|
||||
* Returns the Tag for this file. This will be a union of XiphComment, ID3v1 and ID3v2 tags.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
* \see ID3v1Tag()
|
||||
* \see XiphComment()
|
||||
*/
|
||||
virtual Strawberry_TagLib::TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* 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.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* 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.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* This always creates a Xiph comment, if none exists. The return value
|
||||
* relates to the Xiph comment only.
|
||||
* Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed
|
||||
* in the FLAC specification.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* This always creates a Xiph comment, if none exists. The return value relates to the Xiph comment only.
|
||||
* Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed in the FLAC specification.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the FLAC::Properties for this file. If no audio properties were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file. This will primarily save the XiphComment, but
|
||||
* will also keep any old ID3-tags up to date. If the file
|
||||
* has no XiphComment, one will be constructed from the ID3-tags.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
* Save the file. This will primarily save the XiphComment, but will also keep any old ID3-tags up to date.
|
||||
* If the file has no XiphComment, one will be constructed from the ID3-tags.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v2 tag of the file.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
|
||||
* on disk actually has an ID3v2 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.
|
||||
*
|
||||
* \see hasID3v2Tag()
|
||||
*/
|
||||
* Returns a pointer to the ID3v2 tag of the file.
|
||||
*
|
||||
* 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 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 file on disk has an ID3v2 tag.
|
||||
* Use hasID3v2Tag() to check if the file on disk actually has an ID3v2 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.
|
||||
*
|
||||
* \see hasID3v2Tag()
|
||||
*/
|
||||
ID3v2::Tag *ID3v2Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this returns a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* 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. 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.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this returns a null pointer if there is no valid APE tag.
|
||||
* If \a create is true it will create 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.
|
||||
* 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.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the XiphComment for the file.
|
||||
*
|
||||
* If \a create is false (the default) this returns a null pointer
|
||||
* if there is no valid XiphComment. If \a create is true it will create
|
||||
* 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. 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.
|
||||
*
|
||||
* \see hasXiphComment()
|
||||
*/
|
||||
* Returns a pointer to the XiphComment for the file.
|
||||
*
|
||||
* If \a create is false (the default) this returns a null pointer if there is no valid XiphComment.
|
||||
* If \a create is true it will create 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.
|
||||
* 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.
|
||||
*
|
||||
* \see hasXiphComment()
|
||||
*/
|
||||
Ogg::XiphComment *xiphComment(bool create = false);
|
||||
|
||||
/*!
|
||||
* Set the ID3v2::FrameFactory to something other than the default. This
|
||||
* 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.
|
||||
*/
|
||||
* Returns a list of pictures attached to the FLAC file.
|
||||
*/
|
||||
List<Picture *> pictureList();
|
||||
|
||||
/*!
|
||||
* Removes an attached picture. If \a del is true the picture's memory
|
||||
* will be freed; if it is false, it must be deleted by the user.
|
||||
*/
|
||||
* Removes an attached picture.
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Remove all attached images.
|
||||
*/
|
||||
* Remove all attached images.
|
||||
*/
|
||||
void removePictures();
|
||||
|
||||
/*!
|
||||
* Add a new picture to the file. The file takes ownership of the
|
||||
* picture and will handle freeing its memory.
|
||||
*
|
||||
* \note The file will be saved only after calling save().
|
||||
*/
|
||||
* Add a new picture to the file.
|
||||
* The file takes ownership of the picture and will handle freeing its memory.
|
||||
*
|
||||
* \note The file will be saved only after calling save().
|
||||
*/
|
||||
void addPicture(Picture *picture);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from
|
||||
* the file. By default it removes all tags.
|
||||
*
|
||||
* \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 This won't remove the Vorbis comment block completely. The
|
||||
* vendor ID will be preserved.
|
||||
*/
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the file.
|
||||
* By default it removes all tags.
|
||||
*
|
||||
* \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 This won't remove the Vorbis comment block completely.
|
||||
* The vendor ID will be preserved.
|
||||
*/
|
||||
void strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has a XiphComment.
|
||||
*
|
||||
* \see xiphComment()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has a XiphComment.
|
||||
*
|
||||
* \see xiphComment()
|
||||
*/
|
||||
bool hasXiphComment() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
bool hasID3v1Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
*/
|
||||
bool hasID3v2Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as a FLAC
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as a FLAC file.
|
||||
*
|
||||
* \note This method is designed to do a quick check.
|
||||
* The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
|
|
|
@ -34,9 +34,6 @@ class FLAC::MetadataBlock::MetadataBlockPrivate {
|
|||
MetadataBlockPrivate() {}
|
||||
};
|
||||
|
||||
FLAC::MetadataBlock::MetadataBlock() {
|
||||
d = 0;
|
||||
}
|
||||
FLAC::MetadataBlock::MetadataBlock() : d(nullptr) {}
|
||||
|
||||
FLAC::MetadataBlock::~MetadataBlock() {
|
||||
}
|
||||
FLAC::MetadataBlock::~MetadataBlock() {}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
class TAGLIB_EXPORT MetadataBlock {
|
||||
|
@ -69,7 +68,6 @@ class TAGLIB_EXPORT MetadataBlock {
|
|||
};
|
||||
|
||||
} // namespace FLAC
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ int FLAC::Picture::code() const {
|
|||
}
|
||||
|
||||
bool FLAC::Picture::parse(const ByteVector &data) {
|
||||
|
||||
if (data.size() < 32) {
|
||||
debug("A picture block must contain at least 5 bytes.");
|
||||
return false;
|
||||
|
@ -105,9 +106,11 @@ bool FLAC::Picture::parse(const ByteVector &data) {
|
|||
d->data = data.mid(pos, dataLength);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
ByteVector FLAC::Picture::render() const {
|
||||
|
||||
ByteVector result;
|
||||
result.append(ByteVector::fromUInt(d->type));
|
||||
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(d->data);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
FLAC::Picture::Type FLAC::Picture::type() const {
|
||||
|
|
|
@ -40,8 +40,8 @@ namespace FLAC {
|
|||
class TAGLIB_EXPORT Picture : public MetadataBlock {
|
||||
public:
|
||||
/*!
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
enum Type {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
|
@ -92,102 +92,100 @@ class TAGLIB_EXPORT Picture : public MetadataBlock {
|
|||
~Picture();
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*/
|
||||
* Returns the type of the image.
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type of the image.
|
||||
*/
|
||||
* Sets the type of the image.
|
||||
*/
|
||||
void setType(Type type);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
* Returns the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
* Sets the mime type of the image. This should in most cases be "image/png" or "image/jpeg".
|
||||
*/
|
||||
void setMimeType(const String &m);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*/
|
||||
* Returns a text description of the image.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Returns the width of the image.
|
||||
*/
|
||||
* Returns the width of the image.
|
||||
*/
|
||||
int width() const;
|
||||
|
||||
/*!
|
||||
* Sets the width of the image.
|
||||
*/
|
||||
* Sets the width of the image.
|
||||
*/
|
||||
void setWidth(int w);
|
||||
|
||||
/*!
|
||||
* Returns the height of the image.
|
||||
*/
|
||||
* Returns the height of the image.
|
||||
*/
|
||||
int height() const;
|
||||
|
||||
/*!
|
||||
* Sets the height of the image.
|
||||
*/
|
||||
* Sets the height of the image.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns the number of colors used on the image..
|
||||
*/
|
||||
* Returns the number of colors used on the image..
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Returns the image data.
|
||||
*/
|
||||
* Returns the image data.
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
/*!
|
||||
* Sets the image data.
|
||||
*/
|
||||
* Sets the image data.
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
int code() const;
|
||||
|
||||
/*!
|
||||
* Render the content to the FLAC picture block format.
|
||||
*/
|
||||
* Render the content to the FLAC picture block format.
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
|
@ -201,7 +199,6 @@ class TAGLIB_EXPORT Picture : public MetadataBlock {
|
|||
typedef List<Picture> PictureList;
|
||||
|
||||
} // namespace FLAC
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -53,24 +53,14 @@ class FLAC::Properties::PropertiesPrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style),
|
||||
d(new PropertiesPrivate()) {
|
||||
FLAC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
|
||||
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() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::Properties::length() const {
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int FLAC::Properties::lengthInSeconds() const {
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
@ -91,10 +81,6 @@ int FLAC::Properties::bitsPerSample() const {
|
|||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
int FLAC::Properties::sampleWidth() const {
|
||||
return bitsPerSample();
|
||||
}
|
||||
|
||||
int FLAC::Properties::channels() const {
|
||||
return d->channels;
|
||||
}
|
||||
|
@ -112,6 +98,7 @@ ByteVector FLAC::Properties::signature() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::Properties::read(const ByteVector &data, long streamLength) {
|
||||
|
||||
if (data.size() < 18) {
|
||||
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
|
||||
return;
|
||||
|
@ -155,4 +142,5 @@ void FLAC::Properties::read(const ByteVector &data, long streamLength) {
|
|||
|
||||
if (data.size() >= pos + 16)
|
||||
d->signature = data.mid(pos, 16);
|
||||
|
||||
}
|
||||
|
|
|
@ -39,98 +39,65 @@ class File;
|
|||
//! An implementation of audio property reading for FLAC
|
||||
|
||||
/*!
|
||||
* This reads the data from an FLAC stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
* This reads the data from an FLAC stream found in the AudioProperties API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of FLAC::Properties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*/
|
||||
// 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 ByteVector \a data.
|
||||
*/
|
||||
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Create an instance of FLAC::Properties with the data read from the
|
||||
* FLAC::File \a file.
|
||||
*/
|
||||
// BIC: remove
|
||||
Properties(File *file, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this FLAC::Properties instance.
|
||||
*/
|
||||
* Destroys this FLAC::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \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()
|
||||
*/
|
||||
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInSeconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of bits per audio sample as read from the FLAC
|
||||
* identification header.
|
||||
*/
|
||||
* Returns the number of bits per audio sample as read from the FLAC identification header.
|
||||
*/
|
||||
int bitsPerSample() const;
|
||||
|
||||
/*!
|
||||
* Returns the sample width as read from the FLAC identification
|
||||
* header.
|
||||
*
|
||||
* \note This method is just an alias of bitsPerSample().
|
||||
*
|
||||
* \deprecated
|
||||
*/
|
||||
TAGLIB_DEPRECATED int sampleWidth() const;
|
||||
|
||||
/*!
|
||||
* Return the number of sample frames.
|
||||
*/
|
||||
* Return the number of sample frames.
|
||||
*/
|
||||
unsigned long long sampleFrames() const;
|
||||
|
||||
/*!
|
||||
* Returns the MD5 signature of the uncompressed audio stream as read
|
||||
* from the stream info header.
|
||||
*/
|
||||
* Returns the MD5 signature of the uncompressed audio stream as read from the stream info header.
|
||||
*/
|
||||
ByteVector signature() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
|
||||
|
@ -42,28 +41,28 @@ class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
|
|||
~UnknownMetadataBlock();
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
int code() const;
|
||||
|
||||
/*!
|
||||
* Sets the FLAC metadata block type.
|
||||
*/
|
||||
* Sets the FLAC metadata block type.
|
||||
*/
|
||||
void setCode(int code);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
/*!
|
||||
* Sets the FLAC metadata block type.
|
||||
*/
|
||||
* Sets the FLAC metadata block type.
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Render the content of the block.
|
||||
*/
|
||||
* Render the content of the block.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
private:
|
||||
|
@ -75,7 +74,6 @@ class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
|
|||
};
|
||||
|
||||
} // namespace FLAC
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -35,26 +35,26 @@ using namespace IT;
|
|||
|
||||
class IT::File::FilePrivate {
|
||||
public:
|
||||
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||
: tag(), properties(propertiesStyle) {
|
||||
}
|
||||
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle) : tag(), properties(propertiesStyle) {}
|
||||
|
||||
Mod::Tag tag;
|
||||
IT::Properties properties;
|
||||
};
|
||||
|
||||
IT::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())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
IT::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())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
IT::File::~File() {
|
||||
|
@ -78,6 +78,7 @@ IT::Properties *IT::File::audioProperties() const {
|
|||
}
|
||||
|
||||
bool IT::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("IT::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
|
@ -317,4 +318,5 @@ void IT::File::read(bool) {
|
|||
comment.append(message);
|
||||
d->tag.setComment(comment.toString("\n"));
|
||||
d->tag.setTrackerName("Impulse Tracker");
|
||||
|
||||
}
|
||||
|
|
|
@ -31,67 +31,63 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace IT {
|
||||
|
||||
class TAGLIB_EXPORT File : public Mod::FileBase {
|
||||
public:
|
||||
/*!
|
||||
* Constructs a Impulse Tracker file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*/
|
||||
* Constructs a Impulse Tracker file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
|
||||
* The audio properties are always read.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs a Impulse Tracker file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
* Constructs a Impulse Tracker file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
|
||||
* The audio properties are always read.
|
||||
*
|
||||
* \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,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
Mod::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Forwards to Mod::Tag::properties().
|
||||
* BIC: will be removed once File::toDict() is made virtual
|
||||
*/
|
||||
* Forwards to Mod::Tag::properties().
|
||||
* BIC: will be removed once File::toDict() is made virtual
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Forwards to Mod::Tag::setProperties().
|
||||
* BIC: will be removed once File::setProperties() is made virtual
|
||||
*/
|
||||
* Forwards to Mod::Tag::setProperties().
|
||||
* BIC: will be removed once File::setProperties() is made virtual
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the IT::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the IT::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
IT::Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* \note Saving Impulse Tracker tags is not supported.
|
||||
*/
|
||||
* Save the file.
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* \note Saving Impulse Tracker tags is not supported.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
|
||||
|
@ -104,6 +100,7 @@ class TAGLIB_EXPORT File : public Mod::FileBase {
|
|||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
} // namespace IT
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -65,9 +65,7 @@ class IT::Properties::PropertiesPrivate {
|
|||
unsigned char pitchWheelDepth;
|
||||
};
|
||||
|
||||
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle),
|
||||
d(new PropertiesPrivate()) {
|
||||
}
|
||||
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate()) {}
|
||||
|
||||
IT::Properties::~Properties() {
|
||||
delete d;
|
||||
|
|
|
@ -35,26 +35,24 @@ using namespace Mod;
|
|||
|
||||
class Mod::File::FilePrivate {
|
||||
public:
|
||||
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||
: properties(propertiesStyle) {
|
||||
}
|
||||
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle) : properties(propertiesStyle) {}
|
||||
|
||||
Mod::Tag tag;
|
||||
Mod::Properties properties;
|
||||
};
|
||||
|
||||
Mod::File::File(FileName file, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file),
|
||||
d(new FilePrivate(propertiesStyle)) {
|
||||
Mod::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
Mod::File::File(IOStream *stream, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream),
|
||||
d(new FilePrivate(propertiesStyle)) {
|
||||
Mod::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
Mod::File::~File() {
|
||||
|
@ -78,6 +76,7 @@ PropertyMap Mod::File::setProperties(const PropertyMap &properties) {
|
|||
}
|
||||
|
||||
bool Mod::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("Mod::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
|
@ -96,9 +95,11 @@ bool Mod::File::save() {
|
|||
seek(8, Current);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void Mod::File::read(bool) {
|
||||
|
||||
if (!isOpen())
|
||||
return;
|
||||
|
||||
|
@ -176,4 +177,5 @@ void Mod::File::read(bool) {
|
|||
READ_BYTE(d->properties.setLengthInPatterns);
|
||||
|
||||
d->tag.setComment(comment.toString("\n"));
|
||||
|
||||
}
|
||||
|
|
|
@ -35,66 +35,58 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
|
||||
public:
|
||||
/*!
|
||||
* Constructs a Protracker file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
* Constructs a Protracker file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
|
||||
* The audio properties are always read.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs a Protracker file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*
|
||||
* \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,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
* Constructs a Protracker file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and \a propertiesStyle are ignored.
|
||||
* The audio properties are always read.
|
||||
*
|
||||
* \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, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
Mod::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* Forwards to Mod::Tag::properties().
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* Forwards to Mod::Tag::properties().
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Forwards to Mod::Tag::setProperties().
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* Forwards to Mod::Tag::setProperties().
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
/*!
|
||||
* Returns the Mod::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the Mod::Properties for this file. If no audio properties were read then this will return a null pointer.
|
||||
*/
|
||||
Mod::Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* \note Saving Protracker tags is not supported.
|
||||
*/
|
||||
* Save the file.
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* \note Saving Protracker tags is not supported.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
private:
|
||||
|
@ -108,7 +100,6 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
|
|||
};
|
||||
|
||||
} // namespace Mod
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -30,11 +30,9 @@
|
|||
using namespace Strawberry_TagLib::TagLib;
|
||||
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) {
|
||||
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) {
|
||||
|
||||
ByteVector data(readBlock(size));
|
||||
if (data.size() < size) return false;
|
||||
int index = data.find((char)0);
|
||||
|
@ -53,6 +52,7 @@ bool Mod::FileBase::readString(String &s, unsigned long size) {
|
|||
|
||||
s = data;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
ByteVector data(readBlock(1));
|
||||
if (data.size() < 1) return false;
|
||||
_byte = data[0];
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU16L(unsigned short &number) {
|
||||
|
||||
ByteVector data(readBlock(2));
|
||||
if (data.size() < 2) return false;
|
||||
number = data.toUShort(false);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU32L(unsigned long &number) {
|
||||
|
||||
ByteVector data(readBlock(4));
|
||||
if (data.size() < 4) return false;
|
||||
number = data.toUInt(false);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU16B(unsigned short &number) {
|
||||
|
||||
ByteVector data(readBlock(2));
|
||||
if (data.size() < 2) return false;
|
||||
number = data.toUShort(true);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU32B(unsigned long &number) {
|
||||
|
||||
ByteVector data(readBlock(4));
|
||||
if (data.size() < 4) return false;
|
||||
number = data.toUInt(true);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
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 TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -31,18 +31,14 @@ using namespace Mod;
|
|||
|
||||
class Mod::Properties::PropertiesPrivate {
|
||||
public:
|
||||
PropertiesPrivate() : channels(0),
|
||||
instrumentCount(0),
|
||||
lengthInPatterns(0) {
|
||||
}
|
||||
PropertiesPrivate() : channels(0), instrumentCount(0), lengthInPatterns(0) {}
|
||||
|
||||
int channels;
|
||||
unsigned int instrumentCount;
|
||||
unsigned char lengthInPatterns;
|
||||
};
|
||||
|
||||
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle),
|
||||
d(new PropertiesPrivate()) {
|
||||
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate()) {
|
||||
}
|
||||
|
||||
Mod::Properties::~Properties() {
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
|
@ -65,7 +64,6 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
|
|||
};
|
||||
|
||||
} // namespace Mod
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -33,17 +33,14 @@ using namespace Mod;
|
|||
|
||||
class Mod::Tag::TagPrivate {
|
||||
public:
|
||||
TagPrivate() {
|
||||
}
|
||||
TagPrivate() {}
|
||||
|
||||
String title;
|
||||
String comment;
|
||||
String trackerName;
|
||||
};
|
||||
|
||||
Mod::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(),
|
||||
d(new TagPrivate()) {
|
||||
}
|
||||
Mod::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), d(new TagPrivate()) {}
|
||||
|
||||
Mod::Tag::~Tag() {
|
||||
delete d;
|
||||
|
@ -109,15 +106,18 @@ void Mod::Tag::setTrackerName(const String &trackerName) {
|
|||
}
|
||||
|
||||
PropertyMap Mod::Tag::properties() const {
|
||||
|
||||
PropertyMap properties;
|
||||
properties["TITLE"] = d->title;
|
||||
properties["COMMENT"] = d->comment;
|
||||
if (!(d->trackerName.isEmpty()))
|
||||
properties["TRACKERNAME"] = d->trackerName;
|
||||
return properties;
|
||||
|
||||
}
|
||||
|
||||
PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) {
|
||||
|
||||
PropertyMap properties(origProps);
|
||||
properties.removeEmpty();
|
||||
StringList oneValueSet;
|
||||
|
@ -151,4 +151,5 @@ PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) {
|
|||
properties[*it].erase(properties[*it].begin());
|
||||
}
|
||||
return properties;
|
||||
|
||||
}
|
||||
|
|
|
@ -30,153 +30,141 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
/*!
|
||||
* Tags for module files (Mod, S3M, IT, XM).
|
||||
*
|
||||
* Note that only the \a title is supported as such by most
|
||||
* module file formats. Except for XM files the \a trackerName
|
||||
* is derived from the file format or the flavour of the file
|
||||
* format. For XM files it is stored in the file.
|
||||
*
|
||||
* 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. TagLib does so as well.
|
||||
*/
|
||||
* Tags for module files (Mod, S3M, IT, XM).
|
||||
*
|
||||
* Note that only the \a title is supported as such by most module file formats.
|
||||
* Except for XM files the \a trackerName is derived from the file format or the flavour of the file format.
|
||||
* For XM files it is stored in the file.
|
||||
*
|
||||
* 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.
|
||||
* TagLib does so as well.
|
||||
*
|
||||
*/
|
||||
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
||||
public:
|
||||
Tag();
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Returns the track name; if no track name is present in the tag
|
||||
* String::null will be returned.
|
||||
*/
|
||||
* Returns the track name; if no track name is present in the tag String::null will be returned.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns String::null.
|
||||
*/
|
||||
* Not supported by module files. Therefore always returns String::null.
|
||||
*/
|
||||
virtual String album() const;
|
||||
|
||||
/*!
|
||||
* Returns the track comment derived from the instrument/sample/pattern
|
||||
* names; if no comment is present in the tag String::null will be
|
||||
* returned.
|
||||
*/
|
||||
* Returns the track comment derived from the instrument/sample/pattern
|
||||
* names; if no comment is present in the tag String::null will be returned.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns 0.
|
||||
*/
|
||||
* Not supported by module files. Therefore always returns 0.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* (Mod, S3M, IT) this is derived from the file type or the flavour of
|
||||
* the file type. Therefore only XM files might have an empty
|
||||
* (String::null) tracker name.
|
||||
*/
|
||||
* 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
|
||||
* (Mod, S3M, IT) this is derived from the file type or the flavour of the file type.
|
||||
* Therefore only XM files might have an empty (String::null) tracker name.
|
||||
*/
|
||||
String trackerName() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a title. If \a title is String::null then this
|
||||
* value will be cleared.
|
||||
*
|
||||
* The length limits per file type are (1 character = 1 byte):
|
||||
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20
|
||||
* characters.
|
||||
*/
|
||||
* Sets the title to \a title.
|
||||
* If \a title is String::null then this value will be cleared.
|
||||
*
|
||||
* The length limits per file type are (1 character = 1 byte):
|
||||
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 characters.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
virtual void setAlbum(const String &album);
|
||||
|
||||
/*!
|
||||
* Sets the comment to \a comment. If \a comment is String::null then
|
||||
* this value will be cleared.
|
||||
*
|
||||
* Note that module file formats don't actually support a comment tag.
|
||||
* Instead the names of instruments/patterns/samples are abused as
|
||||
* a multiline comment. Because of this the number of lines in a
|
||||
* 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. 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.
|
||||
*/
|
||||
* Sets the comment to \a comment.
|
||||
* If \a comment is String::null then this value will be cleared.
|
||||
*
|
||||
* Note that module file formats don't actually support a comment tag.
|
||||
* Instead the names of instruments/patterns/samples are abused as a multiline comment.
|
||||
* Because of this the number of lines in a 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.
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Sets the tracker name to \a trackerName. If \a trackerName is
|
||||
* String::null then this value will be cleared.
|
||||
*
|
||||
* Note that only XM files support this tag. Setting the
|
||||
* tracker name for other module file formats will be ignored.
|
||||
*
|
||||
* The length of this tag is limited to 20 characters (1 character
|
||||
* = 1 byte).
|
||||
*/
|
||||
* Sets the tracker name to \a trackerName.
|
||||
* If \a trackerName is String::null then this value will be cleared.
|
||||
*
|
||||
* Note that only XM files support this tag.
|
||||
* Setting the tracker name for other module file formats will be ignored.
|
||||
*
|
||||
* The length of this tag is limited to 20 characters (1 character = 1 byte).
|
||||
*/
|
||||
void setTrackerName(const String &trackerName);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* Since the module tag is very limited, the exported map is as well.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* Since the module tag is very limited, the exported map is as well.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* 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. Additionally, if the map contains tags with multiple values,
|
||||
* all but the first will be contained in the returned map of unsupported
|
||||
* properties.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* 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.
|
||||
* 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 &);
|
||||
|
||||
private:
|
||||
|
@ -188,7 +176,6 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
|||
};
|
||||
|
||||
} // namespace Mod
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -31,13 +31,10 @@
|
|||
|
||||
using namespace Strawberry_TagLib::TagLib;
|
||||
|
||||
const char *MP4::Atom::containers[11] = {
|
||||
"moov", "udta", "mdia", "meta", "ilst",
|
||||
"stbl", "minf", "moof", "traf", "trak",
|
||||
"stsd"
|
||||
};
|
||||
const char *MP4::Atom::containers[11] = { "moov", "udta", "mdia", "meta", "ilst", "stbl", "minf", "moof", "traf", "trak", "stsd" };
|
||||
|
||||
MP4::Atom::Atom(File *file) {
|
||||
|
||||
children.setAutoDelete(true);
|
||||
|
||||
offset = file->tell();
|
||||
|
@ -100,14 +97,14 @@ MP4::Atom::Atom(File *file) {
|
|||
}
|
||||
|
||||
file->seek(offset + length);
|
||||
|
||||
}
|
||||
|
||||
MP4::Atom::~Atom() {
|
||||
}
|
||||
MP4::Atom::~Atom() {}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4) {
|
||||
if (name1 == 0) {
|
||||
MP4::Atom *MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4) {
|
||||
|
||||
if (!name1) {
|
||||
return this;
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atom::findall(const char *_name, bool recursive) {
|
||||
MP4::AtomList MP4::Atom::findall(const char *_name, bool recursive) {
|
||||
|
||||
MP4::AtomList result;
|
||||
for (AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||
if ((*it)->name == _name) {
|
||||
|
@ -130,11 +128,13 @@ MP4::Atom::findall(const char *_name, bool recursive) {
|
|||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
bool MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3) {
|
||||
|
||||
path.append(this);
|
||||
if (name1 == 0) {
|
||||
if (!name1) {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
MP4::Atoms::Atoms(File *file) {
|
||||
|
||||
atoms.setAutoDelete(true);
|
||||
|
||||
file->seek(0, File::End);
|
||||
|
@ -157,23 +159,24 @@ MP4::Atoms::Atoms(File *file) {
|
|||
if (atom->length == 0)
|
||||
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) {
|
||||
if ((*it)->name == name1) {
|
||||
return (*it)->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) {
|
||||
MP4::AtomList MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) {
|
||||
|
||||
MP4::AtomList path;
|
||||
for (AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
|
||||
if ((*it)->name == name1) {
|
||||
|
@ -184,4 +187,5 @@ MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const
|
|||
}
|
||||
}
|
||||
return path;
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class Atom;
|
||||
|
@ -78,6 +77,7 @@ class Atom {
|
|||
public:
|
||||
Atom(File *file);
|
||||
~Atom();
|
||||
|
||||
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);
|
||||
AtomList findall(const char *name, bool recursive = false);
|
||||
|
@ -96,13 +96,13 @@ class Atoms {
|
|||
public:
|
||||
Atoms(File *file);
|
||||
~Atoms();
|
||||
|
||||
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 atoms;
|
||||
};
|
||||
|
||||
} // namespace MP4
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ using namespace Strawberry_TagLib::TagLib;
|
|||
|
||||
class MP4::CoverArt::CoverArtPrivate : public RefCounter {
|
||||
public:
|
||||
CoverArtPrivate() : RefCounter(),
|
||||
format(MP4::CoverArt::JPEG) {}
|
||||
CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {}
|
||||
|
||||
Format format;
|
||||
ByteVector data;
|
||||
|
|
|
@ -33,14 +33,13 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class TAGLIB_EXPORT CoverArt {
|
||||
public:
|
||||
/*!
|
||||
* This describes the image type.
|
||||
*/
|
||||
* This describes the image type.
|
||||
*/
|
||||
enum Format {
|
||||
JPEG = TypeJPEG,
|
||||
PNG = TypePNG,
|
||||
|
@ -55,13 +54,13 @@ class TAGLIB_EXPORT CoverArt {
|
|||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
//! Format of the image
|
||||
|
@ -78,7 +77,6 @@ class TAGLIB_EXPORT CoverArt {
|
|||
typedef List<CoverArt> CoverArtList;
|
||||
|
||||
} // namespace MP4
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ using namespace Strawberry_TagLib::TagLib;
|
|||
|
||||
namespace {
|
||||
bool checkValid(const MP4::AtomList &list) {
|
||||
|
||||
for (MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||
|
||||
if ((*it)->length == 0)
|
||||
|
@ -46,14 +47,13 @@ bool checkValid(const MP4::AtomList &list) {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class MP4::File::FilePrivate {
|
||||
public:
|
||||
FilePrivate() : tag(0),
|
||||
atoms(0),
|
||||
properties(0) {}
|
||||
FilePrivate() : tag(nullptr), atoms(nullptr), properties(nullptr) {}
|
||||
|
||||
~FilePrivate() {
|
||||
delete atoms;
|
||||
|
@ -71,26 +71,30 @@ class MP4::File::FilePrivate {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool MP4::File::isSupported(IOStream *stream) {
|
||||
|
||||
// An MP4 file has to have an "ftyp" box first.
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 8, false);
|
||||
return id.containsAt("ftyp", 4);
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
|
||||
d(new FilePrivate()) {
|
||||
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
|
||||
d(new FilePrivate()) {
|
||||
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
MP4::File::~File() {
|
||||
|
@ -120,6 +124,7 @@ MP4::File::audioProperties() const {
|
|||
}
|
||||
|
||||
void MP4::File::read(bool readProperties) {
|
||||
|
||||
if (!isValid())
|
||||
return;
|
||||
|
||||
|
@ -139,9 +144,11 @@ void MP4::File::read(bool readProperties) {
|
|||
if (readProperties) {
|
||||
d->properties = new Properties(this, d->atoms);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MP4::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("MP4::File::save() -- File is read only.");
|
||||
return false;
|
||||
|
@ -153,8 +160,9 @@ bool MP4::File::save() {
|
|||
}
|
||||
|
||||
return d->tag->save();
|
||||
|
||||
}
|
||||
|
||||
bool MP4::File::hasMP4Tag() const {
|
||||
return (d->atoms->find("moov", "udta", "meta", "ilst") != 0);
|
||||
return (d->atoms->find("moov", "udta", "meta", "ilst") != nullptr);
|
||||
}
|
||||
|
|
|
@ -41,92 +41,85 @@ namespace MP4 {
|
|||
class Atoms;
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for MP4 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 MP4 files.
|
||||
*/
|
||||
* This implements and provides an interface for MP4 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 MP4 files.
|
||||
*/
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* Constructs an MP4 file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
* Constructs an MP4 file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an MP4 file from \a stream. 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
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
* Constructs an MP4 file from \a stream.
|
||||
* 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
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the MP4 tag of the file.
|
||||
*
|
||||
* MP4::Tag implements the tag interface, so this serves as the
|
||||
* 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. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
* Returns a pointer to the MP4 tag of the file.
|
||||
*
|
||||
* MP4::Tag implements the tag interface, so this serves as the 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.
|
||||
* It will be deleted when the file (object) is destroyed.
|
||||
*/
|
||||
Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Removes unsupported properties. Forwards to the actual Tag's
|
||||
* removeUnsupportedProperties() function.
|
||||
*/
|
||||
* Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
|
||||
*/
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the MP4 audio properties for this file.
|
||||
*/
|
||||
* Returns the MP4 audio properties for this file.
|
||||
*/
|
||||
Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an MP4 tag, or the
|
||||
* file has a Metadata Item List (ilst) atom.
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an MP4 tag, or the file has a Metadata Item List (ilst) atom.
|
||||
*/
|
||||
bool hasMP4Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as an ASF
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as an ASF file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
|
@ -137,7 +130,6 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
|||
};
|
||||
|
||||
} // namespace MP4
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -32,9 +32,7 @@ using namespace Strawberry_TagLib::TagLib;
|
|||
|
||||
class MP4::Item::ItemPrivate : public RefCounter {
|
||||
public:
|
||||
ItemPrivate() : RefCounter(),
|
||||
valid(true),
|
||||
atomDataType(TypeUndefined) {}
|
||||
ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {}
|
||||
|
||||
bool valid;
|
||||
AtomDataType atomDataType;
|
||||
|
@ -59,8 +57,7 @@ MP4::Item::Item(const Item &item) : d(item.d) {
|
|||
d->ref();
|
||||
}
|
||||
|
||||
MP4::Item &
|
||||
MP4::Item::operator=(const Item &item) {
|
||||
MP4::Item &MP4::Item::operator=(const Item &item) {
|
||||
Item(item).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
@ -129,38 +126,31 @@ int MP4::Item::toInt() const {
|
|||
return d->m_int;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
MP4::Item::toByte() const {
|
||||
unsigned char MP4::Item::toByte() const {
|
||||
return d->m_byte;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Item::toUInt() const {
|
||||
unsigned int MP4::Item::toUInt() const {
|
||||
return d->m_uint;
|
||||
}
|
||||
|
||||
long long
|
||||
MP4::Item::toLongLong() const {
|
||||
long long MP4::Item::toLongLong() const {
|
||||
return d->m_longlong;
|
||||
}
|
||||
|
||||
MP4::Item::IntPair
|
||||
MP4::Item::toIntPair() const {
|
||||
MP4::Item::IntPair MP4::Item::toIntPair() const {
|
||||
return d->m_intPair;
|
||||
}
|
||||
|
||||
StringList
|
||||
MP4::Item::toStringList() const {
|
||||
StringList MP4::Item::toStringList() const {
|
||||
return d->m_stringList;
|
||||
}
|
||||
|
||||
ByteVectorList
|
||||
MP4::Item::toByteVectorList() const {
|
||||
ByteVectorList MP4::Item::toByteVectorList() const {
|
||||
return d->m_byteVectorList;
|
||||
}
|
||||
|
||||
MP4::CoverArtList
|
||||
MP4::Item::toCoverArtList() const {
|
||||
MP4::CoverArtList MP4::Item::toCoverArtList() const {
|
||||
return d->m_coverArtList;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class TAGLIB_EXPORT Item {
|
||||
|
@ -45,13 +44,13 @@ class TAGLIB_EXPORT 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
~Item();
|
||||
|
@ -87,7 +86,6 @@ class TAGLIB_EXPORT Item {
|
|||
};
|
||||
|
||||
} // namespace MP4
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -54,8 +54,7 @@ class MP4::Properties::PropertiesPrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style),
|
||||
d(new PropertiesPrivate()) {
|
||||
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
|
||||
read(file, atoms);
|
||||
}
|
||||
|
||||
|
@ -71,10 +70,6 @@ int MP4::Properties::sampleRate() const {
|
|||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int MP4::Properties::length() const {
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int MP4::Properties::lengthInSeconds() const {
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
@ -105,13 +100,14 @@ MP4::Properties::codec() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MP4::Properties::read(File *file, Atoms *atoms) {
|
||||
|
||||
MP4::Atom *moov = atoms->find("moov");
|
||||
if (!moov) {
|
||||
debug("MP4: Atom 'moov' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *trak = 0;
|
||||
MP4::Atom *trak = nullptr;
|
||||
ByteVector data;
|
||||
|
||||
const MP4::AtomList trakList = moov->findall("trak");
|
||||
|
@ -127,7 +123,7 @@ void MP4::Properties::read(File *file, Atoms *atoms) {
|
|||
if (data.containsAt("soun", 16)) {
|
||||
break;
|
||||
}
|
||||
trak = 0;
|
||||
trak = nullptr;
|
||||
}
|
||||
if (!trak) {
|
||||
debug("MP4: No audio tracks");
|
||||
|
@ -207,4 +203,5 @@ void MP4::Properties::read(File *file, Atoms *atoms) {
|
|||
if (drms) {
|
||||
d->encrypted = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class Atoms;
|
||||
|
@ -50,60 +49,49 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
|
|||
virtual ~Properties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \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()
|
||||
*/
|
||||
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInSeconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of bits per audio sample.
|
||||
*/
|
||||
* Returns the number of bits per audio sample.
|
||||
*/
|
||||
virtual int bitsPerSample() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file is encrypted.
|
||||
*/
|
||||
* Returns whether or not the file is encrypted.
|
||||
*/
|
||||
bool isEncrypted() const;
|
||||
|
||||
/*!
|
||||
* Returns the codec used in the file.
|
||||
*/
|
||||
* Returns the codec used in the file.
|
||||
*/
|
||||
Codec codec() const;
|
||||
|
||||
private:
|
||||
|
@ -114,7 +102,6 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
|
|||
};
|
||||
|
||||
} // namespace MP4
|
||||
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -34,18 +34,17 @@ using namespace Strawberry_TagLib::TagLib;
|
|||
|
||||
class MP4::Tag::TagPrivate {
|
||||
public:
|
||||
TagPrivate() : file(0),
|
||||
atoms(0) {}
|
||||
TagPrivate() : file(nullptr), atoms(nullptr) {}
|
||||
|
||||
Strawberry_TagLib::TagLib::File *file;
|
||||
Atoms *atoms;
|
||||
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()) {
|
||||
|
||||
d->file = file;
|
||||
d->atoms = atoms;
|
||||
|
||||
|
@ -113,8 +112,8 @@ MP4::Tag::~Tag() {
|
|||
delete d;
|
||||
}
|
||||
|
||||
MP4::AtomDataList
|
||||
MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
|
||||
MP4::AtomDataList MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
|
||||
|
||||
AtomDataList result;
|
||||
ByteVector data = d->file->readBlock(atom->length - 8);
|
||||
int i = 0;
|
||||
|
@ -152,47 +151,58 @@ MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
|
|||
i++;
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ByteVectorList
|
||||
MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
|
||||
ByteVectorList MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm) {
|
||||
|
||||
AtomDataList data = parseData2(atom, expectedFlags, freeForm);
|
||||
ByteVectorList result;
|
||||
for (AtomDataList::ConstIterator it = data.begin(); it != data.end(); ++it) {
|
||||
result.append(it->data);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseInt(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
addItem(atom->name, (int)data[0].toShort());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseUInt(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
addItem(atom->name, data[0].toUInt());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseLongLong(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
addItem(atom->name, data[0].toLongLong());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseByte(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
addItem(atom->name, static_cast<unsigned char>(data[0].at(0)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseGnre(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseIntPair(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
const int a = data[0].toShort(2U);
|
||||
const int b = data[0].toShort(4U);
|
||||
addItem(atom->name, MP4::Item(a, b));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseBool(const MP4::Atom *atom) {
|
||||
|
||||
ByteVectorList data = parseData(atom);
|
||||
if (!data.isEmpty()) {
|
||||
bool value = data[0].size() ? data[0][0] != '\0' : false;
|
||||
addItem(atom->name, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) {
|
||||
|
||||
ByteVectorList data = parseData(atom, expectedFlags);
|
||||
if (!data.isEmpty()) {
|
||||
StringList value;
|
||||
|
@ -228,9 +244,11 @@ void MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) {
|
|||
}
|
||||
addItem(atom->name, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseFreeForm(const MP4::Atom *atom) {
|
||||
|
||||
AtomDataList data = parseData2(atom, -1, true);
|
||||
if (data.size() > 2) {
|
||||
AtomDataList::ConstIterator itBegin = data.begin();
|
||||
|
@ -267,9 +285,11 @@ void MP4::Tag::parseFreeForm(const MP4::Atom *atom) {
|
|||
addItem(name, item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::parseCovr(const MP4::Atom *atom) {
|
||||
|
||||
MP4::CoverArtList value;
|
||||
ByteVector data = d->file->readBlock(atom->length - 8);
|
||||
unsigned int pos = 0;
|
||||
|
@ -299,106 +319,117 @@ void MP4::Tag::parseCovr(const MP4::Atom *atom) {
|
|||
}
|
||||
if (!value.isEmpty())
|
||||
addItem(atom->name, value);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::padIlst(const ByteVector &data, int length) const {
|
||||
ByteVector MP4::Tag::padIlst(const ByteVector &data, int length) const {
|
||||
|
||||
if (length == -1) {
|
||||
length = ((data.size() + 1023) & ~1023) - data.size();
|
||||
}
|
||||
return renderAtom("free", ByteVector(length, '\1'));
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const {
|
||||
ByteVector MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const {
|
||||
return ByteVector::fromUInt(data.size() + 8) + name + data;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const {
|
||||
ByteVector MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const {
|
||||
|
||||
ByteVector result;
|
||||
for (ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) {
|
||||
result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + *it));
|
||||
}
|
||||
return renderAtom(name, result);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
|
||||
return renderData(name, TypeInteger, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromShort(item.toInt()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromUInt(item.toUInt()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromLongLong(item.toLongLong()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(1, item.toByte()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(2, '\0') +
|
||||
ByteVector::fromShort(item.toIntPair().first) +
|
||||
ByteVector::fromShort(item.toIntPair().second) +
|
||||
ByteVector(2, '\0'));
|
||||
return renderData(name, TypeImplicit, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(2, '\0') +
|
||||
ByteVector::fromShort(item.toIntPair().first) +
|
||||
ByteVector::fromShort(item.toIntPair().second));
|
||||
return renderData(name, TypeImplicit, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderText(const ByteVector &name, const MP4::Item &item, int flags) const {
|
||||
ByteVector MP4::Tag::renderText(const ByteVector &name, const MP4::Item &item, int flags) const {
|
||||
|
||||
ByteVectorList data;
|
||||
StringList value = item.toStringList();
|
||||
for (StringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
|
||||
data.append(it->data(String::UTF8));
|
||||
}
|
||||
return renderData(name, flags, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const {
|
||||
|
||||
ByteVector data;
|
||||
MP4::CoverArtList value = item.toCoverArtList();
|
||||
for (MP4::CoverArtList::ConstIterator it = value.begin(); it != value.end(); ++it) {
|
||||
data.append(renderAtom("data", ByteVector::fromUInt(it->format()) + ByteVector(4, '\0') + it->data()));
|
||||
}
|
||||
return renderAtom(name, data);
|
||||
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const {
|
||||
ByteVector MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const {
|
||||
|
||||
StringList header = StringList::split(name, ":");
|
||||
if (header.size() != 3) {
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
bool MP4::Tag::save() {
|
||||
|
||||
ByteVector data;
|
||||
for (MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
|
||||
const String name = it->first;
|
||||
|
@ -496,9 +529,11 @@ bool MP4::Tag::save() {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) {
|
||||
|
||||
if (static_cast<int>(path.size()) <= ignore)
|
||||
return;
|
||||
|
||||
|
@ -525,6 +560,7 @@ void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) {
|
|||
}
|
||||
|
||||
void MP4::Tag::updateOffsets(long delta, long offset) {
|
||||
|
||||
MP4::Atom *moov = d->atoms->find("moov");
|
||||
if (moov) {
|
||||
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) {
|
||||
|
||||
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");
|
||||
|
@ -612,9 +650,11 @@ void MP4::Tag::saveNew(ByteVector data) {
|
|||
|
||||
d->file->seek(offset);
|
||||
path.back()->children.prepend(new Atom(d->file));
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) {
|
||||
|
||||
AtomList::ConstIterator it = path.end();
|
||||
|
||||
MP4::Atom *ilst = *(--it);
|
||||
|
@ -660,52 +700,46 @@ void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) {
|
|||
updateParents(path, delta, 1);
|
||||
updateOffsets(delta, offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::title() const {
|
||||
String MP4::Tag::title() const {
|
||||
if (d->items.contains("\251nam"))
|
||||
return d->items["\251nam"].toStringList().toString(", ");
|
||||
return String();
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::artist() const {
|
||||
String MP4::Tag::artist() const {
|
||||
if (d->items.contains("\251ART"))
|
||||
return d->items["\251ART"].toStringList().toString(", ");
|
||||
return String();
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::album() const {
|
||||
String MP4::Tag::album() const {
|
||||
if (d->items.contains("\251alb"))
|
||||
return d->items["\251alb"].toStringList().toString(", ");
|
||||
return String();
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::comment() const {
|
||||
String MP4::Tag::comment() const {
|
||||
if (d->items.contains("\251cmt"))
|
||||
return d->items["\251cmt"].toStringList().toString(", ");
|
||||
return String();
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::genre() const {
|
||||
String MP4::Tag::genre() const {
|
||||
if (d->items.contains("\251gen"))
|
||||
return d->items["\251gen"].toStringList().toString(", ");
|
||||
return String();
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Tag::year() const {
|
||||
unsigned int MP4::Tag::year() const {
|
||||
if (d->items.contains("\251day"))
|
||||
return d->items["\251day"].toStringList().toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Tag::track() const {
|
||||
unsigned int MP4::Tag::track() const {
|
||||
if (d->items.contains("trkn"))
|
||||
return d->items["trkn"].toIntPair().first;
|
||||
return 0;
|
||||
|
@ -732,31 +766,31 @@ void MP4::Tag::setGenre(const String &value) {
|
|||
}
|
||||
|
||||
void MP4::Tag::setYear(unsigned int value) {
|
||||
|
||||
if (value == 0) {
|
||||
d->items.erase("\251day");
|
||||
}
|
||||
else {
|
||||
d->items["\251day"] = StringList(String::number(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::setTrack(unsigned int value) {
|
||||
|
||||
if (value == 0) {
|
||||
d->items.erase("trkn");
|
||||
}
|
||||
else {
|
||||
d->items["trkn"] = MP4::Item(value, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MP4::Tag::isEmpty() const {
|
||||
return d->items.isEmpty();
|
||||
}
|
||||
|
||||
MP4::ItemMap &MP4::Tag::itemListMap() {
|
||||
return d->items;
|
||||
}
|
||||
|
||||
const MP4::ItemMap &MP4::Tag::itemMap() const {
|
||||
return d->items;
|
||||
}
|
||||
|
@ -835,16 +869,19 @@ const char *keyTranslation[][2] = {
|
|||
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||
|
||||
String translateKey(const String &key) {
|
||||
|
||||
for (size_t i = 0; i < keyTranslationSize; ++i) {
|
||||
if (key == keyTranslation[i][0])
|
||||
return keyTranslation[i][1];
|
||||
}
|
||||
|
||||
return String();
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
PropertyMap MP4::Tag::properties() const {
|
||||
|
||||
PropertyMap props;
|
||||
for (MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
|
||||
const String key = translateKey(it->first);
|
||||
|
@ -872,14 +909,18 @@ PropertyMap MP4::Tag::properties() const {
|
|||
}
|
||||
}
|
||||
return props;
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::removeUnsupportedProperties(const StringList &props) {
|
||||
|
||||
for (StringList::ConstIterator it = props.begin(); it != props.end(); ++it)
|
||||
d->items.erase(*it);
|
||||
|
||||
}
|
||||
|
||||
PropertyMap MP4::Tag::setProperties(const PropertyMap &props) {
|
||||
|
||||
static Map<String, String> reverseKeyMap;
|
||||
if (reverseKeyMap.isEmpty()) {
|
||||
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||
|
@ -928,13 +969,16 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props) {
|
|||
}
|
||||
|
||||
return ignoredProps;
|
||||
|
||||
}
|
||||
|
||||
void MP4::Tag::addItem(const String &name, const Item &value) {
|
||||
|
||||
if (!d->items.contains(name)) {
|
||||
d->items.insert(name, value);
|
||||
}
|
||||
else {
|
||||
debug("MP4: Ignoring duplicate atom \"" + name + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,13 +37,8 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
*/
|
||||
TAGLIB_DEPRECATED typedef Strawberry_TagLib::TagLib::Map<String, Item> ItemListMap;
|
||||
typedef Strawberry_TagLib::TagLib::Map<String, Item> ItemMap;
|
||||
|
||||
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 bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* \deprecated Use the item() and setItem() API instead
|
||||
*/
|
||||
TAGLIB_DEPRECATED ItemMap &itemListMap();
|
||||
|
||||
/*!
|
||||
* Returns a string-keyed map of the MP4::Items for this tag.
|
||||
*/
|
||||
* Returns a string-keyed map of the MP4::Items for this tag.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Removes the entry with \a key from the tag, or does nothing if it does
|
||||
* not exist.
|
||||
*/
|
||||
* Removes the entry with \a key from the tag, or does nothing if it does not exist.
|
||||
*/
|
||||
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;
|
||||
|
||||
PropertyMap properties() const;
|
||||
|
@ -107,10 +95,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
|||
PropertyMap setProperties(const PropertyMap &properties);
|
||||
|
||||
private:
|
||||
AtomDataList parseData2(const Atom *atom, int expectedFlags = -1,
|
||||
bool freeForm = false);
|
||||
ByteVectorList parseData(const Atom *atom, int expectedFlags = -1,
|
||||
bool freeForm = false);
|
||||
AtomDataList parseData2(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 parseFreeForm(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 renderAtom(const ByteVector &name, const ByteVector &data) const;
|
||||
ByteVector renderData(const ByteVector &name, int flags,
|
||||
const ByteVectorList &data) const;
|
||||
ByteVector renderText(const ByteVector &name, const Item &item,
|
||||
int flags = TypeUTF8) const;
|
||||
ByteVector renderData(const ByteVector &name, int flags, const ByteVectorList &data) const;
|
||||
ByteVector renderText(const ByteVector &name, const Item &item, int flags = TypeUTF8) const;
|
||||
ByteVector renderFreeForm(const String &name, const Item &item) const;
|
||||
ByteVector renderBool(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 TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
|
|
|
@ -48,10 +48,10 @@ class MPC::File::FilePrivate {
|
|||
FilePrivate() : APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
ID3v2Header(0),
|
||||
ID3v2Header(nullptr),
|
||||
ID3v2Location(-1),
|
||||
ID3v2Size(0),
|
||||
properties(0) {}
|
||||
properties(nullptr) {}
|
||||
|
||||
~FilePrivate() {
|
||||
delete ID3v2Header;
|
||||
|
@ -77,27 +77,31 @@ class MPC::File::FilePrivate {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool MPC::File::isSupported(IOStream *stream) {
|
||||
|
||||
// A newer MPC file has to start with "MPCK" or "MP+", but older files don't
|
||||
// have keys to do a quick check.
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 4, false);
|
||||
return (id == "MPCK" || id.startsWith("MP+"));
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
|
||||
d(new FilePrivate()) {
|
||||
MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
|
||||
d(new FilePrivate()) {
|
||||
MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate()) {
|
||||
|
||||
if (isOpen())
|
||||
read(readProperties);
|
||||
|
||||
}
|
||||
|
||||
MPC::File::~File() {
|
||||
|
@ -128,6 +132,7 @@ MPC::Properties *MPC::File::audioProperties() const {
|
|||
}
|
||||
|
||||
bool MPC::File::save() {
|
||||
|
||||
if (readOnly()) {
|
||||
debug("MPC::File::save() -- File is read only.");
|
||||
return false;
|
||||
|
@ -211,6 +216,7 @@ bool MPC::File::save() {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
ID3v1::Tag *MPC::File::ID3v1Tag(bool create) {
|
||||
|
@ -222,23 +228,21 @@ APE::Tag *MPC::File::APETag(bool create) {
|
|||
}
|
||||
|
||||
void MPC::File::strip(int tags) {
|
||||
|
||||
if (tags & ID3v1)
|
||||
d->tag.set(MPCID3v1Index, 0);
|
||||
d->tag.set(MPCID3v1Index, nullptr);
|
||||
|
||||
if (tags & APE)
|
||||
d->tag.set(MPCAPEIndex, 0);
|
||||
d->tag.set(MPCAPEIndex, nullptr);
|
||||
|
||||
if (!ID3v1Tag())
|
||||
APETag(true);
|
||||
|
||||
if (tags & ID3v2) {
|
||||
delete d->ID3v2Header;
|
||||
d->ID3v2Header = 0;
|
||||
d->ID3v2Header = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MPC::File::remove(int tags) {
|
||||
strip(tags);
|
||||
}
|
||||
|
||||
bool MPC::File::hasID3v1Tag() const {
|
||||
|
@ -254,6 +258,7 @@ bool MPC::File::hasAPETag() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPC::File::read(bool readProperties) {
|
||||
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = Utils::findID3v2(this);
|
||||
|
@ -307,4 +312,5 @@ void MPC::File::read(bool readProperties) {
|
|||
|
||||
d->properties = new Properties(this, streamLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,31 +49,27 @@ class Tag;
|
|||
//! An 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
|
||||
* properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped
|
||||
* and ignored.
|
||||
*/
|
||||
* This is implementation of MPC metadata.
|
||||
*
|
||||
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream properties from the file.
|
||||
* ID3v2 tags are invalid in MPC-files, but will be skipped and ignored.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace MPC {
|
||||
|
||||
//! An implementation of TagLib::File with MPC specific methods
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
* The only invalid tag combination supported is an ID3v1 tag after an APE tag.
|
||||
*/
|
||||
* 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.
|
||||
* The only invalid tag combination supported is an ID3v1 tag after an APE tag.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
* This set of flags is used for various operations and is suitable for being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
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
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
* Constructs an MPC file from \a file.
|
||||
* If \a readProperties is true the file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an MPC file from \a stream. 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
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
* Constructs an MPC file from \a stream.
|
||||
* 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 responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||
* or a combination of the two.
|
||||
*/
|
||||
* Returns the Tag for this file.
|
||||
* This will be an APE tag, an ID3v1 tag or a combination of the two.
|
||||
*/
|
||||
virtual Strawberry_TagLib::TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only the APE
|
||||
* tag will be converted to the PropertyMap.
|
||||
*/
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only the APE tag will be converted to the PropertyMap.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Affects only the APEv2 tag which will be created if necessary.
|
||||
* If an ID3v1 tag exists, it will be updated as well.
|
||||
*/
|
||||
* Implements the unified property interface -- import function.
|
||||
* Affects only the APEv2 tag which will be created if necessary.
|
||||
* If an ID3v1 tag exists, it will be updated as well.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the MPC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
* Returns the MPC::Properties for this file.
|
||||
* If no audio properties were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
* Saves the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this returns a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* 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. 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.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this returns a null pointer if there is no valid APE tag.
|
||||
* If \a create is true it will create 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.
|
||||
* 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.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* 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
|
||||
* an APE tag if one does not exist and returns a valid pointer. 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
|
||||
* 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.
|
||||
*
|
||||
* \see hasAPETag()
|
||||
*/
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* 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 an APE tag if one does not exist and returns a valid pointer.
|
||||
* 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 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.
|
||||
*
|
||||
* \see hasAPETag()
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it removes all tags.
|
||||
*
|
||||
* \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.
|
||||
*/
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the file. By default it removes all tags.
|
||||
*
|
||||
* \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.
|
||||
*/
|
||||
void strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
* \see strip
|
||||
*/
|
||||
TAGLIB_DEPRECATED void remove(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
bool hasID3v1Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an APE tag.
|
||||
*
|
||||
* \see APETag()
|
||||
*/
|
||||
* Returns whether or not the file on disk actually has an APE tag.
|
||||
*
|
||||
* \see APETag()
|
||||
*/
|
||||
bool hasAPETag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as an MPC
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
* Returns whether or not the given \a stream can be opened as an MPC file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
|
|
|
@ -64,13 +64,12 @@ class MPC::Properties::PropertiesPrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style),
|
||||
d(new PropertiesPrivate()) {
|
||||
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
|
||||
readSV7(data, streamLength);
|
||||
}
|
||||
|
||||
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style),
|
||||
d(new PropertiesPrivate()) {
|
||||
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) {
|
||||
|
||||
ByteVector magic = file->readBlock(4);
|
||||
if (magic == "MPCK") {
|
||||
// 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
|
||||
readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MPC::Properties::~Properties() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
int MPC::Properties::length() const {
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int MPC::Properties::lengthInSeconds() const {
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
@ -144,6 +140,7 @@ int MPC::Properties::albumPeak() const {
|
|||
|
||||
namespace {
|
||||
unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) {
|
||||
|
||||
sizeLength = 0;
|
||||
eof = false;
|
||||
|
||||
|
@ -160,19 +157,26 @@ unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) {
|
|||
tmp = b[0];
|
||||
size = (size << 7) | (tmp & 0x7F);
|
||||
sizeLength++;
|
||||
} while ((tmp & 0x80));
|
||||
}
|
||||
while ((tmp & 0x80));
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
unsigned long readSize(const ByteVector &data, unsigned int &pos) {
|
||||
|
||||
unsigned char tmp;
|
||||
unsigned long size = 0;
|
||||
|
||||
do {
|
||||
tmp = data[pos++];
|
||||
size = (size << 7) | (tmp & 0x7F);
|
||||
} while ((tmp & 0x80) && (pos < data.size()));
|
||||
}
|
||||
while ((tmp & 0x80) && (pos < data.size()));
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
void MPC::Properties::readSV8(File *file, long streamLength) {
|
||||
|
||||
bool readSH = false, readRG = false;
|
||||
|
||||
while (!readSH && !readRG) {
|
||||
|
@ -269,9 +274,11 @@ void MPC::Properties::readSV8(File *file, long streamLength) {
|
|||
file->seek(dataSize, File::Current);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MPC::Properties::readSV7(const ByteVector &data, long streamLength) {
|
||||
|
||||
if (data.startsWith("MP+")) {
|
||||
d->version = data[3] & 15;
|
||||
if (d->version < 7)
|
||||
|
@ -340,4 +347,5 @@ void MPC::Properties::readSV7(const ByteVector &data, long streamLength) {
|
|||
if (d->bitrate == 0)
|
||||
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,105 +41,92 @@ static const unsigned int HeaderSize = 8 * 7;
|
|||
//! An implementation of audio property reading for MPC
|
||||
|
||||
/*!
|
||||
* This reads the data from an MPC stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
* This reads the data from an MPC stream found in the AudioProperties API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of MPC::Properties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*
|
||||
* This constructor is deprecated. It only works for MPC version up to 7.
|
||||
*/
|
||||
* Create an instance of MPC::Properties with the data read from the ByteVector \a data.
|
||||
*
|
||||
* This constructor is deprecated. It only works for MPC version up to 7.
|
||||
*/
|
||||
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Create an instance of MPC::Properties with the data read directly
|
||||
* from a MPC::File.
|
||||
*/
|
||||
* Create an instance of MPC::Properties with the data read directly from a MPC::File.
|
||||
*/
|
||||
Properties(File *file, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this MPC::Properties instance.
|
||||
*/
|
||||
* Destroys this MPC::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \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()
|
||||
*/
|
||||
* Returns the length of the file in seconds.
|
||||
* The length is rounded down to the nearest whole second.
|
||||
*
|
||||
* \see lengthInMilliseconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInSeconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the version of the bitstream (SV4-SV8)
|
||||
*/
|
||||
* Returns the version of the bitstream (SV4-SV8)
|
||||
*/
|
||||
int mpcVersion() const;
|
||||
|
||||
unsigned int totalFrames() const;
|
||||
unsigned int sampleFrames() const;
|
||||
|
||||
/*!
|
||||
* Returns the track gain as an integer value,
|
||||
* to convert to dB: trackGain in dB = 64.82 - (trackGain / 256)
|
||||
*/
|
||||
* Returns the track gain as an integer value,
|
||||
* to convert to dB: trackGain in dB = 64.82 - (trackGain / 256)
|
||||
*/
|
||||
int trackGain() const;
|
||||
|
||||
/*!
|
||||
* Returns the track peak as an integer value,
|
||||
* to convert to dB: trackPeak in dB = trackPeak / 256
|
||||
* to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768
|
||||
*/
|
||||
* Returns the track peak as an integer value,
|
||||
* to convert to dB: trackPeak in dB = trackPeak / 256
|
||||
* to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768
|
||||
*/
|
||||
int trackPeak() const;
|
||||
|
||||
/*!
|
||||
* Returns the album gain as an integer value,
|
||||
* to convert to dB: albumGain in dB = 64.82 - (albumGain / 256)
|
||||
*/
|
||||
* Returns the album gain as an integer value,
|
||||
* to convert to dB: albumGain in dB = 64.82 - (albumGain / 256)
|
||||
*/
|
||||
int albumGain() const;
|
||||
|
||||
/*!
|
||||
* Returns the album peak as an integer value,
|
||||
* to convert to dB: albumPeak in dB = albumPeak / 256
|
||||
* to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768
|
||||
*/
|
||||
* Returns the album peak as an integer value,
|
||||
* to convert to dB: albumPeak in dB = albumPeak / 256
|
||||
* to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768
|
||||
*/
|
||||
int albumPeak() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -226,35 +226,43 @@ const int genresSize = sizeof(genres) / sizeof(genres[0]);
|
|||
} // namespace
|
||||
|
||||
StringList ID3v1::genreList() {
|
||||
|
||||
StringList l;
|
||||
for (int i = 0; i < genresSize; i++) {
|
||||
l.append(genres[i]);
|
||||
}
|
||||
|
||||
return l;
|
||||
|
||||
}
|
||||
|
||||
ID3v1::GenreMap ID3v1::genreMap() {
|
||||
|
||||
GenreMap m;
|
||||
for (int i = 0; i < genresSize; i++) {
|
||||
m.insert(genres[i], i);
|
||||
}
|
||||
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
String ID3v1::genre(int i) {
|
||||
|
||||
if (i >= 0 && i < genresSize)
|
||||
return String(genres[i]); // always make a copy
|
||||
else
|
||||
return String();
|
||||
|
||||
}
|
||||
|
||||
int ID3v1::genreIndex(const String &name) {
|
||||
|
||||
for (int i = 0; i < genresSize; ++i) {
|
||||
if (name == genres[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
return 255;
|
||||
|
||||
}
|
||||
|
|
|
@ -37,29 +37,25 @@ namespace ID3v1 {
|
|||
typedef Map<String, int> GenreMap;
|
||||
|
||||
/*!
|
||||
* Returns the list of canonical ID3v1 genre names in the order that they
|
||||
* are listed in the standard.
|
||||
*/
|
||||
* Returns the list of canonical ID3v1 genre names in the order that they are listed in the standard.
|
||||
*/
|
||||
StringList TAGLIB_EXPORT genreList();
|
||||
|
||||
/*!
|
||||
* A "reverse mapping" that goes from the canonical ID3v1 genre name to the
|
||||
* respective genre number. genreMap()["Rock"] ==
|
||||
*/
|
||||
* A "reverse mapping" that goes from the canonical ID3v1 genre name to the respective genre number. genreMap()["Rock"] ==
|
||||
*/
|
||||
GenreMap TAGLIB_EXPORT genreMap();
|
||||
|
||||
/*!
|
||||
* Returns the name of the genre at \a index in the ID3v1 genre list. If
|
||||
* \a index is out of range -- less than zero or greater than 191 -- a null
|
||||
* string will be returned.
|
||||
*/
|
||||
* Returns the name of the genre at \a index in the ID3v1 genre list.
|
||||
* If \a index is out of range -- less than zero or greater than 191 -- a null string will be returned.
|
||||
*/
|
||||
String TAGLIB_EXPORT genre(int index);
|
||||
|
||||
/*!
|
||||
* Returns the genre index for the (case sensitive) genre \a name. If the
|
||||
* genre is not in the list 255 (which signifies an unknown genre in ID3v1)
|
||||
* will be returned.
|
||||
*/
|
||||
* Returns the genre index for the (case sensitive) genre \a name.
|
||||
* If the genre is not in the list 255 (which signifies an unknown genre in ID3v1) will be returned.
|
||||
*/
|
||||
int TAGLIB_EXPORT genreIndex(const String &name);
|
||||
} // namespace ID3v1
|
||||
} // namespace TagLib
|
||||
|
|
|
@ -39,7 +39,7 @@ const ID3v1::StringHandler *stringHandler = &defaultStringHandler;
|
|||
|
||||
class ID3v1::Tag::TagPrivate {
|
||||
public:
|
||||
TagPrivate() : file(0),
|
||||
TagPrivate() : file(nullptr),
|
||||
tagOffset(0),
|
||||
track(0),
|
||||
genre(255) {}
|
||||
|
@ -68,22 +68,22 @@ String ID3v1::StringHandler::parse(const ByteVector &data) const {
|
|||
}
|
||||
|
||||
ByteVector ID3v1::StringHandler::render(const String &s) const {
|
||||
|
||||
if (s.isLatin1())
|
||||
return s.data(String::Latin1);
|
||||
else
|
||||
return ByteVector();
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v1::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(),
|
||||
d(new TagPrivate()) {
|
||||
}
|
||||
ID3v1::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(), 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->tagOffset = tagOffset;
|
||||
|
||||
|
@ -95,6 +95,7 @@ ID3v1::Tag::~Tag() {
|
|||
}
|
||||
|
||||
ByteVector ID3v1::Tag::render() const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(fileIdentifier());
|
||||
|
@ -108,6 +109,7 @@ ByteVector ID3v1::Tag::render() const {
|
|||
data.append(char(d->genre));
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::fileIdentifier() {
|
||||
|
@ -190,6 +192,7 @@ void ID3v1::Tag::setStringHandler(const StringHandler *handler) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ID3v1::Tag::read() {
|
||||
|
||||
if (d->file && d->file->isValid()) {
|
||||
d->file->seek(d->tagOffset);
|
||||
// read the tag -- always 128 bytes
|
||||
|
@ -201,9 +204,11 @@ void ID3v1::Tag::read() {
|
|||
else
|
||||
debug("ID3v1 tag is not valid or could not be read at the specified offset.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ID3v1::Tag::parse(const ByteVector &data) {
|
||||
|
||||
int offset = 3;
|
||||
|
||||
d->title = stringHandler->parse(data.mid(offset, 30));
|
||||
|
@ -235,4 +240,5 @@ void ID3v1::Tag::parse(const ByteVector &data) {
|
|||
offset += 30;
|
||||
|
||||
d->genre = static_cast<unsigned char>(data[offset]);
|
||||
|
||||
}
|
||||
|
|
|
@ -42,94 +42,86 @@ namespace ID3v1 {
|
|||
//! A abstraction for the string to data encoding in ID3v1 tags.
|
||||
|
||||
/*!
|
||||
* ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In
|
||||
* practice it does not. TagLib by default only supports ISO-8859-1 data
|
||||
* in ID3v1 tags.
|
||||
*
|
||||
* However by subclassing this class and reimplementing parse() and render()
|
||||
* and setting your reimplementation as the default with
|
||||
* ID3v1::Tag::setStringHandler() you can define how you would like these
|
||||
* transformations to be done.
|
||||
*
|
||||
* \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1
|
||||
* tags. Please consider disabling the writing of ID3v1 tags in the case
|
||||
* that the data is not ISO-8859-1.
|
||||
*
|
||||
* \see ID3v1::Tag::setStringHandler()
|
||||
*/
|
||||
* ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In practice it does not.
|
||||
* TagLib by default only supports ISO-8859-1 data in ID3v1 tags.
|
||||
*
|
||||
* However by subclassing this class and reimplementing parse() and render() and setting your reimplementation as the default with
|
||||
* ID3v1::Tag::setStringHandler() you can define how you would like these transformations to be done.
|
||||
*
|
||||
* \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1 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 {
|
||||
TAGLIB_IGNORE_MISSING_DESTRUCTOR
|
||||
|
||||
public:
|
||||
// BIC: Add virtual destructor.
|
||||
StringHandler();
|
||||
|
||||
/*!
|
||||
* Decode a string from \a data. The default implementation assumes that
|
||||
* \a data is an ISO-8859-1 (Latin1) character array.
|
||||
*/
|
||||
* Decode a string from \a data.
|
||||
* The default implementation assumes that \a data is an ISO-8859-1 (Latin1) character array.
|
||||
*/
|
||||
virtual String parse(const ByteVector &data) const;
|
||||
|
||||
/*!
|
||||
* Encode a ByteVector with the data from \a s. The default implementation
|
||||
* assumes that \a s is an ISO-8859-1 (Latin1) string. 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
|
||||
* instead do not write an ID3v1 tag in the case that the data is not
|
||||
* ISO-8859-1.
|
||||
*/
|
||||
* Encode a ByteVector with the data from \a s.
|
||||
* The default implementation assumes that \a s is an ISO-8859-1 (Latin1) string.
|
||||
* 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
|
||||
* instead do not write an ID3v1 tag in the case that the data is not ISO-8859-1.
|
||||
*/
|
||||
virtual ByteVector render(const String &s) const;
|
||||
};
|
||||
|
||||
//! The main class in the ID3v1 implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of the ID3v1 format. ID3v1 is both the simplest
|
||||
* and most common of tag formats but is rather limited. 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
|
||||
* provided by ID3v1.
|
||||
*
|
||||
* ID3v1 tags should generally only contain Latin1 information. However because
|
||||
* many applications do not follow this rule there is now support for overriding
|
||||
* the ID3v1 string handling using the ID3v1::StringHandler class. Please see
|
||||
* the documentation for that class for more information.
|
||||
*
|
||||
* \see StringHandler
|
||||
*
|
||||
* \note Most fields are truncated to a maximum of 28-30 bytes. The
|
||||
* truncation happens automatically when the tag is rendered.
|
||||
*/
|
||||
* This is an implementation of the ID3v1 format.
|
||||
* ID3v1 is both the simplest and most common of tag formats but is rather limited.
|
||||
* 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 provided by ID3v1.
|
||||
*
|
||||
* ID3v1 tags should generally only contain Latin1 information.
|
||||
* However because many applications do not follow this rule there is now support for overriding
|
||||
* the ID3v1 string handling using the ID3v1::StringHandler class.
|
||||
* Please see the documentation for that class for more information.
|
||||
*
|
||||
* \see StringHandler
|
||||
*
|
||||
* \note Most fields are truncated to a maximum of 28-30 bytes.
|
||||
* The truncation happens automatically when the tag is rendered.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
||||
public:
|
||||
/*!
|
||||
* Create an ID3v1 tag with default values.
|
||||
*/
|
||||
* Create an ID3v1 tag with default values.
|
||||
*/
|
||||
Tag();
|
||||
|
||||
/*!
|
||||
* Create an ID3v1 tag and parse the data in \a file starting at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
* Create an ID3v1 tag and parse the data in \a file starting at \a tagOffset.
|
||||
*/
|
||||
Tag(File *file, long tagOffset);
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Renders the in memory values to a ByteVector suitable for writing to
|
||||
* the file.
|
||||
*/
|
||||
* Renders the in memory values to a ByteVector suitable for writing to the file.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the string "TAG" suitable for usage in locating the tag in a
|
||||
* file.
|
||||
*/
|
||||
* Returns the string "TAG" suitable for usage in locating the tag in a file.
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
// Reimplementations.
|
||||
|
@ -151,41 +143,37 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
|||
virtual void setTrack(unsigned int i);
|
||||
|
||||
/*!
|
||||
* Returns the genre in number.
|
||||
*
|
||||
* \note Normally 255 indicates that this tag contains no genre.
|
||||
*/
|
||||
* Returns the genre in number.
|
||||
*
|
||||
* \note Normally 255 indicates that this tag contains no genre.
|
||||
*/
|
||||
unsigned int genreNumber() const;
|
||||
|
||||
/*!
|
||||
* Sets the genre in number to \a i.
|
||||
*
|
||||
* \note Valid value is from 0 up to 255. Normally 255 indicates that
|
||||
* this tag contains no genre.
|
||||
*/
|
||||
* Sets the genre in number to \a i.
|
||||
*
|
||||
* \note Valid value is from 0 up to 255. Normally 255 indicates that this tag contains no genre.
|
||||
*/
|
||||
void setGenreNumber(unsigned int i);
|
||||
|
||||
/*!
|
||||
* Sets the string handler that decides how the ID3v1 data will be
|
||||
* 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.
|
||||
*
|
||||
* \note The caller is responsible for deleting the previous handler
|
||||
* as needed after it is released.
|
||||
*
|
||||
* \see StringHandler
|
||||
*/
|
||||
* Sets the string handler that decides how the ID3v1 data will be 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.
|
||||
*
|
||||
* \note The caller is responsible for deleting the previous handler as needed after it is released.
|
||||
*
|
||||
* \see StringHandler
|
||||
*/
|
||||
static void setStringHandler(const StringHandler *handler);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
|
@ -195,6 +183,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
|
|||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace ID3v1
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -33,8 +33,7 @@ using namespace ID3v2;
|
|||
|
||||
class AttachedPictureFrame::AttachedPictureFramePrivate {
|
||||
public:
|
||||
AttachedPictureFramePrivate() : textEncoding(String::Latin1),
|
||||
type(AttachedPictureFrame::Other) {}
|
||||
AttachedPictureFramePrivate() : textEncoding(String::Latin1), type(AttachedPictureFrame::Other) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
|
@ -47,12 +46,9 @@ class AttachedPictureFrame::AttachedPictureFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC"),
|
||||
d(new AttachedPictureFramePrivate()) {
|
||||
}
|
||||
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC"), d(new AttachedPictureFramePrivate()) {}
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data),
|
||||
d(new AttachedPictureFramePrivate()) {
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data), d(new AttachedPictureFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -110,6 +106,7 @@ void AttachedPictureFrame::setPicture(const ByteVector &p) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
if (data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
|
@ -130,9 +127,11 @@ void AttachedPictureFrame::parseFields(const ByteVector &data) {
|
|||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::renderFields() const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
@ -146,14 +145,14 @@ ByteVector AttachedPictureFrame::renderFields() const {
|
|||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new AttachedPictureFramePrivate()) {
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h), d(new AttachedPictureFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
|
@ -162,6 +161,7 @@ AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrameV22::parseFields(const ByteVector &data) {
|
||||
|
||||
if (data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
|
@ -189,9 +189,11 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data) {
|
|||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
|
||||
}
|
||||
|
||||
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h) {
|
||||
|
||||
// set v2.2 header to make fieldData work correctly
|
||||
setHeader(h, true);
|
||||
|
||||
|
@ -201,4 +203,5 @@ AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header
|
|||
Frame::Header *newHeader = new Frame::Header("APIC");
|
||||
newHeader->setFrameSize(h->frameSize());
|
||||
setHeader(newHeader, true);
|
||||
|
||||
}
|
||||
|
|
|
@ -32,25 +32,23 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An ID3v2 attached picture frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 attached pictures. Pictures may be
|
||||
* included in tags, one per APIC frame (but there may be multiple APIC
|
||||
* frames in a single tag). These pictures are usually in either JPEG or
|
||||
* PNG format.
|
||||
*/
|
||||
* This is an implementation of ID3v2 attached pictures.
|
||||
* Pictures may be included in tags, one per APIC frame (but there may be multiple APIC frames in a single tag).
|
||||
* These pictures are usually in either JPEG or PNG format.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
enum Type {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
|
@ -97,108 +95,106 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
|
|||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty picture frame. The description, content and text
|
||||
* encoding should be set manually.
|
||||
*/
|
||||
* Constructs an empty picture frame.
|
||||
* The description, content and text encoding should be set manually.
|
||||
*/
|
||||
AttachedPictureFrame();
|
||||
|
||||
/*!
|
||||
* Constructs an AttachedPicture frame based on \a data.
|
||||
*/
|
||||
* Constructs an AttachedPicture frame based on \a data.
|
||||
*/
|
||||
explicit AttachedPictureFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the AttahcedPictureFrame instance.
|
||||
*/
|
||||
* Destroys the AttahcedPictureFrame instance.
|
||||
*/
|
||||
virtual ~AttachedPictureFrame();
|
||||
|
||||
/*!
|
||||
* Returns a string containing the description and mime-type
|
||||
*/
|
||||
* Returns a string containing the description and mime-type
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding used for the description.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
*/
|
||||
* Returns the text encoding used for the description.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Set the text encoding used for the description.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
* Set the text encoding used for the description.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setTextEncoding(String::Type t);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
* Returns the mime type of the image.
|
||||
* This should in most cases be "image/png" or "image/jpeg".
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
* Sets the mime type of the image.
|
||||
* This should in most cases be "image/png" or "image/jpeg".
|
||||
*/
|
||||
void setMimeType(const String &m);
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
void setType(Type t);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
ByteVector picture() const;
|
||||
|
||||
/*!
|
||||
* Sets the image data to \a p. \a p should be of the type specified in
|
||||
* this frame's mime-type specification.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
* Sets the image data to \a p. \a p should be of the type specified in this frame's mime-type specification.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setPicture(const ByteVector &p);
|
||||
|
||||
protected:
|
||||
|
@ -222,6 +218,7 @@ class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame {
|
|||
AttachedPictureFrameV22(const ByteVector &data, Header *h);
|
||||
friend class FrameFactory;
|
||||
};
|
||||
|
||||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -35,7 +35,7 @@ using namespace ID3v2;
|
|||
|
||||
class ChapterFrame::ChapterFramePrivate {
|
||||
public:
|
||||
ChapterFramePrivate() : tagHeader(0),
|
||||
ChapterFramePrivate() : tagHeader(nullptr),
|
||||
startTime(0),
|
||||
endTime(0),
|
||||
startOffset(0),
|
||||
|
@ -57,19 +57,14 @@ class ChapterFrame::ChapterFramePrivate {
|
|||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : ID3v2::Frame(data),
|
||||
d(new ChapterFramePrivate()) {
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : ID3v2::Frame(data), d(new ChapterFramePrivate()) {
|
||||
d->tagHeader = tagHeader;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
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()) {
|
||||
// setElementID has a workaround for a previously silly API where you had to
|
||||
// specifically include the null byte.
|
||||
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()) {
|
||||
|
||||
// setElementID has a workaround for a previously silly API where you had to specifically include the null byte.
|
||||
|
||||
setElementID(elementID);
|
||||
|
||||
|
@ -82,6 +77,7 @@ ChapterFrame::ChapterFrame(const ByteVector &elementID,
|
|||
it != embeddedFrames.end();
|
||||
++it)
|
||||
addEmbeddedFrame(*it);
|
||||
|
||||
}
|
||||
|
||||
ChapterFrame::~ChapterFrame() {
|
||||
|
@ -109,10 +105,12 @@ unsigned int ChapterFrame::endOffset() const {
|
|||
}
|
||||
|
||||
void ChapterFrame::setElementID(const ByteVector &eID) {
|
||||
|
||||
d->elementID = eID;
|
||||
|
||||
if (d->elementID.endsWith(char(0)))
|
||||
d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
|
||||
|
||||
}
|
||||
|
||||
void ChapterFrame::setStartTime(const unsigned int &sT) {
|
||||
|
@ -149,6 +147,7 @@ void ChapterFrame::addEmbeddedFrame(Frame *frame) {
|
|||
}
|
||||
|
||||
void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del) {
|
||||
|
||||
// remove the frame from the frame list
|
||||
FrameList::Iterator it = d->embeddedFrameList.find(frame);
|
||||
d->embeddedFrameList.erase(it);
|
||||
|
@ -160,15 +159,19 @@ void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del) {
|
|||
// ...and delete as desired
|
||||
if (del)
|
||||
delete frame;
|
||||
|
||||
}
|
||||
|
||||
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id) {
|
||||
|
||||
FrameList l = d->embeddedFrameListMap[id];
|
||||
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeEmbeddedFrame(*it, true);
|
||||
|
||||
}
|
||||
|
||||
String ChapterFrame::toString() const {
|
||||
|
||||
String s = String(d->elementID) +
|
||||
": start time: " + String::number(d->startTime) +
|
||||
", end time: " + String::number(d->endTime);
|
||||
|
@ -189,18 +192,21 @@ String ChapterFrame::toString() const {
|
|||
}
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
PropertyMap ChapterFrame::asProperties() const {
|
||||
|
||||
PropertyMap map;
|
||||
|
||||
map.unsupportedData().append(frameID() + String("/") + d->elementID);
|
||||
|
||||
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");
|
||||
|
||||
for (ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
|
@ -212,9 +218,11 @@ ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVec
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
void ChapterFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
unsigned int size = data.size();
|
||||
if (size < 18) {
|
||||
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();
|
||||
addEmbeddedFrame(frame);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector ChapterFrame::renderFields() const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->elementID);
|
||||
|
@ -271,10 +281,12 @@ ByteVector ChapterFrame::renderFields() const {
|
|||
data.append((*it)->render());
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new ChapterFramePrivate()) {
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h), d(new ChapterFramePrivate()) {
|
||||
|
||||
d->tagHeader = tagHeader;
|
||||
parseFields(fieldData(data));
|
||||
|
||||
}
|
||||
|
|
|
@ -32,13 +32,12 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 chapter frames. The purpose of this
|
||||
* frame is to describe a single chapter within an audio file.
|
||||
*/
|
||||
* This is an implementation of ID3v2 chapter frames.
|
||||
* The purpose of this frame is to describe a single chapter within an audio file.
|
||||
*/
|
||||
|
||||
//! An implementation of ID3v2 chapter frames
|
||||
|
||||
|
@ -47,175 +46,162 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
|
|||
|
||||
public:
|
||||
/*!
|
||||
* Creates a chapter frame based on \a data. \a tagHeader is required as
|
||||
* the internal frames are parsed based on the tag version.
|
||||
*/
|
||||
* Creates a chapter frame based on \a data.
|
||||
* \a tagHeader is required as the internal frames are parsed based on the tag version.
|
||||
*/
|
||||
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Creates a chapter frame with the element ID \a elementID, start time
|
||||
* \a startTime, end time \a endTime, start offset \a startOffset,
|
||||
* end offset \a endOffset and optionally a list of embedded frames,
|
||||
* whose ownership will then be taken over by this Frame, in
|
||||
* \a embeededFrames;
|
||||
*
|
||||
* All times are in milliseconds.
|
||||
*/
|
||||
* Creates a chapter frame with the element ID \a elementID,
|
||||
* start time \a startTime, end time \a endTime, start offset \a startOffset,
|
||||
* end offset \a endOffset and optionally a list of embedded frames,
|
||||
* whose ownership will then be taken over by this Frame, in \a embeededFrames;
|
||||
*
|
||||
* All times are in milliseconds.
|
||||
*/
|
||||
ChapterFrame(const ByteVector &elementID,
|
||||
unsigned int startTime, unsigned int endTime,
|
||||
unsigned int startOffset, unsigned int endOffset,
|
||||
const FrameList &embeddedFrames = FrameList());
|
||||
|
||||
/*!
|
||||
* Destroys the frame.
|
||||
*/
|
||||
* Destroys the frame.
|
||||
*/
|
||||
virtual ~ChapterFrame();
|
||||
|
||||
/*!
|
||||
* Returns the element ID of the frame. Element ID
|
||||
* is a null terminated string, however it's not human-readable.
|
||||
*
|
||||
* \see setElementID()
|
||||
*/
|
||||
* Returns the element ID of the frame.
|
||||
* Element ID is a null terminated string, however it's not human-readable.
|
||||
*
|
||||
* \see setElementID()
|
||||
*/
|
||||
ByteVector elementID() const;
|
||||
|
||||
/*!
|
||||
* Returns time of chapter's start (in milliseconds).
|
||||
*
|
||||
* \see setStartTime()
|
||||
*/
|
||||
* Returns time of chapter's start (in milliseconds).
|
||||
*
|
||||
* \see setStartTime()
|
||||
*/
|
||||
unsigned int startTime() const;
|
||||
|
||||
/*!
|
||||
* Returns time of chapter's end (in milliseconds).
|
||||
*
|
||||
* \see setEndTime()
|
||||
*/
|
||||
* Returns time of chapter's end (in milliseconds).
|
||||
*
|
||||
* \see setEndTime()
|
||||
*/
|
||||
unsigned int endTime() const;
|
||||
|
||||
/*!
|
||||
* Returns zero based byte offset (count of bytes from the beginning
|
||||
* of the audio file) of chapter's start.
|
||||
*
|
||||
* \note If returned value is 0xFFFFFFFF, start time should be used instead.
|
||||
* \see setStartOffset()
|
||||
*/
|
||||
* Returns zero based byte offset (count of bytes from the beginning of the audio file) of chapter's start.
|
||||
*
|
||||
* \note If returned value is 0xFFFFFFFF, start time should be used instead.
|
||||
* \see setStartOffset()
|
||||
*/
|
||||
unsigned int startOffset() const;
|
||||
|
||||
/*!
|
||||
* Returns zero based byte offset (count of bytes from the beginning
|
||||
* of the audio file) of chapter's end.
|
||||
*
|
||||
* \note If returned value is 0xFFFFFFFF, end time should be used instead.
|
||||
* \see setEndOffset()
|
||||
*/
|
||||
* Returns zero based byte offset (count of bytes from the beginning of the audio file) of chapter's end.
|
||||
*
|
||||
* \note If returned value is 0xFFFFFFFF, end time should be used instead.
|
||||
* \see setEndOffset()
|
||||
*/
|
||||
unsigned int endOffset() const;
|
||||
|
||||
/*!
|
||||
* Sets the element ID of the frame to \a eID. If \a eID isn't
|
||||
* null terminated, a null char is appended automatically.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
* Sets the element ID of the frame to \a eID. If \a eID isn't null terminated, a null char is appended automatically.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
void setElementID(const ByteVector &eID);
|
||||
|
||||
/*!
|
||||
* Sets time of chapter's start (in milliseconds) to \a sT.
|
||||
*
|
||||
* \see startTime()
|
||||
*/
|
||||
* Sets time of chapter's start (in milliseconds) to \a sT.
|
||||
*
|
||||
* \see startTime()
|
||||
*/
|
||||
void setStartTime(const unsigned int &sT);
|
||||
|
||||
/*!
|
||||
* Sets time of chapter's end (in milliseconds) to \a eT.
|
||||
*
|
||||
* \see endTime()
|
||||
*/
|
||||
* Sets time of chapter's end (in milliseconds) to \a eT.
|
||||
*
|
||||
* \see endTime()
|
||||
*/
|
||||
void setEndTime(const unsigned int &eT);
|
||||
|
||||
/*!
|
||||
* Sets zero based byte offset (count of bytes from the beginning
|
||||
* of the audio file) of chapter's start to \a sO.
|
||||
*
|
||||
* \see startOffset()
|
||||
*/
|
||||
* Sets zero based byte offset (count of bytes from the beginning of the audio file) of chapter's start to \a sO.
|
||||
*
|
||||
* \see startOffset()
|
||||
*/
|
||||
void setStartOffset(const unsigned int &sO);
|
||||
|
||||
/*!
|
||||
* Sets zero based byte offset (count of bytes from the beginning
|
||||
* of the audio file) of chapter's end to \a eO.
|
||||
*
|
||||
* \see endOffset()
|
||||
*/
|
||||
* Sets zero based byte offset (count of bytes from the beginning of the audio file) of chapter's end to \a eO.
|
||||
*
|
||||
* \see endOffset()
|
||||
*/
|
||||
void setEndOffset(const unsigned int &eO);
|
||||
|
||||
/*!
|
||||
* Returns a reference to the frame list map. 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
|
||||
* embedded frames. Many frame types allow multiple instances of the same
|
||||
* frame type so this is a map of lists. In most cases however there will
|
||||
* only be a single frame of a certain type.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*
|
||||
* \see embeddedFrameList()
|
||||
*/
|
||||
* Returns a reference to the frame list map.
|
||||
* 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 embedded frames.
|
||||
* Many frame types allow multiple instances of the same rame type so this is a map of lists.
|
||||
* In most cases however there will only be a single frame of a certain type.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*
|
||||
* \see embeddedFrameList()
|
||||
*/
|
||||
const FrameListMap &embeddedFrameListMap() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the embedded frame list. This is an FrameList
|
||||
* of all of the frames embedded in the CHAP frame in the order that they
|
||||
* were parsed.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*/
|
||||
* Returns a reference to the embedded frame list.
|
||||
* This is an FrameList of all of the frames embedded in the CHAP frame in the order that they were parsed.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \warning You should not modify this data structure directly,
|
||||
* instead use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*/
|
||||
const FrameList &embeddedFrameList() const;
|
||||
|
||||
/*!
|
||||
* 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. This
|
||||
* is just a convenience and is equivalent to:
|
||||
*
|
||||
* \code
|
||||
* embeddedFrameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see embeddedFrameListMap()
|
||||
*/
|
||||
* 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.
|
||||
* This is just a convenience and is equivalent to:
|
||||
*
|
||||
* \code
|
||||
* embeddedFrameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see embeddedFrameListMap()
|
||||
*/
|
||||
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
|
||||
|
||||
/*!
|
||||
* Add an embedded frame to the CHAP frame. 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
|
||||
* returned by embeddedFrameList()
|
||||
*/
|
||||
* Add an embedded frame to the CHAP frame.
|
||||
* 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 returned by embeddedFrameList()
|
||||
*/
|
||||
void addEmbeddedFrame(Frame *frame);
|
||||
|
||||
/*!
|
||||
* Remove an embedded frame from the CHAP frame. 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
|
||||
* returned by embeddedFrameList()
|
||||
*/
|
||||
* Remove an embedded frame from the CHAP frame.
|
||||
* 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 returned by embeddedFrameList()
|
||||
*/
|
||||
void removeEmbeddedFrame(Frame *frame, bool del = true);
|
||||
|
||||
/*!
|
||||
* Remove all embedded frames of type \a id from the CHAP frame and free their
|
||||
* memory.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list
|
||||
* returned by embeddedFrameList()
|
||||
*/
|
||||
* Remove all embedded frames of type \a id from the CHAP frame and free their memory.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
|
||||
*/
|
||||
void removeEmbeddedFrames(const ByteVector &id);
|
||||
|
||||
virtual String toString() const;
|
||||
|
@ -223,12 +209,11 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
|
|||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* 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. This
|
||||
* can be used to link CTOC and CHAP frames together.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
* 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.
|
||||
* This can be used to link CTOC and CHAP frames together.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID);
|
||||
|
||||
protected:
|
||||
|
@ -243,6 +228,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
|
|||
class ChapterFramePrivate;
|
||||
ChapterFramePrivate *d;
|
||||
};
|
||||
|
||||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -47,13 +47,11 @@ class CommentsFrame::CommentsFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM"),
|
||||
d(new CommentsFramePrivate()) {
|
||||
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM"), d(new CommentsFramePrivate()) {
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data),
|
||||
d(new CommentsFramePrivate()) {
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data), d(new CommentsFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -98,6 +96,7 @@ void CommentsFrame::setTextEncoding(String::Type encoding) {
|
|||
}
|
||||
|
||||
PropertyMap CommentsFrame::asProperties() const {
|
||||
|
||||
String key = description().upper();
|
||||
PropertyMap map;
|
||||
if (key.isEmpty() || key == "COMMENT")
|
||||
|
@ -105,10 +104,11 @@ PropertyMap CommentsFrame::asProperties() const {
|
|||
else
|
||||
map.insert("COMMENT:" + key, text());
|
||||
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");
|
||||
|
||||
for (ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
|
@ -120,6 +120,7 @@ CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const Str
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -127,6 +128,7 @@ CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const Str
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CommentsFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
if (data.size() < 5) {
|
||||
debug("A comment frame must contain at least 5 bytes.");
|
||||
return;
|
||||
|
@ -149,9 +151,11 @@ void CommentsFrame::parseFields(const ByteVector &data) {
|
|||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::renderFields() const {
|
||||
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = d->textEncoding;
|
||||
|
@ -166,13 +170,13 @@ ByteVector CommentsFrame::renderFields() const {
|
|||
v.append(d->text.data(encoding));
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new CommentsFramePrivate()) {
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h), d(new CommentsFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -31,129 +31,124 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 comments
|
||||
|
||||
/*!
|
||||
* This implements the ID3v2 comment format. An ID3v2 comment consists of
|
||||
* a language encoding, a description and a single text field.
|
||||
*/
|
||||
* This implements the ID3v2 comment format. An ID3v2 comment consists of
|
||||
* a language encoding, a description and a single text field.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT CommentsFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty comment frame that will use the text encoding
|
||||
* \a encoding.
|
||||
*/
|
||||
* Construct an empty comment frame that will use the text encoding \a encoding.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this CommentFrame instance.
|
||||
*/
|
||||
* Destroys this CommentFrame instance.
|
||||
*/
|
||||
virtual ~CommentsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* 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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
* 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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this comment.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
* Returns the description of this comment.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see setText()
|
||||
*/
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see setText()
|
||||
*/
|
||||
String text() const;
|
||||
|
||||
/*!
|
||||
* 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 languageCode.
|
||||
*
|
||||
* \see language()
|
||||
*/
|
||||
* 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 languageCode.
|
||||
*
|
||||
* \see language()
|
||||
*/
|
||||
void setLanguage(const ByteVector &languageCode);
|
||||
|
||||
/*!
|
||||
* Sets the description of the comment to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
* Sets the description of the comment to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the text portion of the comment to \a s.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Sets the text portion of the comment to \a s.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual void setText(const String &s);
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Sets the text encoding to be used when rendering this frame to \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Parses this frame as PropertyMap with a single key.
|
||||
* - if description() is empty or "COMMENT", the key will be "COMMENT"
|
||||
* - if description() is not a valid PropertyMap key, the frame will be
|
||||
* marked unsupported by an entry "COMM/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "COMMENT:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
*/
|
||||
* Parses this frame as PropertyMap with a single key.
|
||||
* - if description() is empty or "COMMENT", the key will be "COMMENT"
|
||||
* - if description() is not a valid PropertyMap key, the frame will be
|
||||
* marked unsupported by an entry "COMM/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "COMMENT:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Comments each have a unique description. This searches for a comment
|
||||
* frame with the description \a d and returns a pointer to it. If no
|
||||
* frame is found that matches the given description null is returned.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
* Comments each have a unique description.
|
||||
* This searches for a comment frame with the description \a d and returns a pointer to it.
|
||||
* If no frame is found that matches the given description null is returned.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
static CommentsFrame *findByDescription(const Tag *tag, const String &d);
|
||||
|
||||
protected:
|
||||
|
@ -164,8 +159,8 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
CommentsFrame(const ByteVector &data, Header *h);
|
||||
CommentsFrame(const CommentsFrame &);
|
||||
CommentsFrame &operator=(const CommentsFrame &);
|
||||
|
@ -177,4 +172,5 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,12 +43,9 @@ class EventTimingCodesFrame::EventTimingCodesFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame() : Frame("ETCO"),
|
||||
d(new EventTimingCodesFramePrivate()) {
|
||||
}
|
||||
EventTimingCodesFrame::EventTimingCodesFrame() : Frame("ETCO"), d(new EventTimingCodesFramePrivate()) {}
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) : Frame(data),
|
||||
d(new EventTimingCodesFramePrivate()) {
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) : Frame(data), d(new EventTimingCodesFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -85,6 +82,7 @@ void EventTimingCodesFrame::setSynchedEvents(
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EventTimingCodesFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
const int end = data.size();
|
||||
if (end < 1) {
|
||||
debug("An event timing codes frame must contain at least 1 byte.");
|
||||
|
@ -101,28 +99,28 @@ void EventTimingCodesFrame::parseFields(const ByteVector &data) {
|
|||
pos += 4;
|
||||
d->synchedEvents.append(SynchedEvent(time, type));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector EventTimingCodesFrame::renderFields() const {
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(d->timestampFormat));
|
||||
for (SynchedEventList::ConstIterator it = d->synchedEvents.begin();
|
||||
it != d->synchedEvents.end();
|
||||
++it) {
|
||||
for (SynchedEventList::ConstIterator it = d->synchedEvents.begin(); it != d->synchedEvents.end(); ++it) {
|
||||
const SynchedEvent &entry = *it;
|
||||
v.append(char(entry.type));
|
||||
v.append(ByteVector::fromUInt(entry.time));
|
||||
}
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new EventTimingCodesFramePrivate()) {
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) : Frame(h), d(new EventTimingCodesFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -31,20 +31,19 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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 {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Specifies the timestamp format used.
|
||||
*/
|
||||
* Specifies the timestamp format used.
|
||||
*/
|
||||
enum TimestampFormat {
|
||||
//! The timestamp is of unknown format.
|
||||
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 {
|
||||
Padding = 0x00,
|
||||
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 {
|
||||
SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {}
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Construct an empty event timing codes frame.
|
||||
*/
|
||||
* Construct an empty event timing codes frame.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this EventTimingCodesFrame instance.
|
||||
*/
|
||||
* Destroys this EventTimingCodesFrame instance.
|
||||
*/
|
||||
virtual ~EventTimingCodesFrame();
|
||||
|
||||
/*!
|
||||
* Returns a null string.
|
||||
*/
|
||||
* Returns a null string.
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the timestamp format.
|
||||
*/
|
||||
* Returns the timestamp format.
|
||||
*/
|
||||
TimestampFormat timestampFormat() const;
|
||||
|
||||
/*!
|
||||
* Returns the events with the time stamps.
|
||||
*/
|
||||
* Returns the events with the time stamps.
|
||||
*/
|
||||
SynchedEventList synchedEvents() const;
|
||||
|
||||
/*!
|
||||
* Set the timestamp format.
|
||||
*
|
||||
* \see timestampFormat()
|
||||
*/
|
||||
* Set the timestamp format.
|
||||
*
|
||||
* \see timestampFormat()
|
||||
*/
|
||||
void setTimestampFormat(TimestampFormat f);
|
||||
|
||||
/*!
|
||||
* Sets the text with the time stamps.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Sets the text with the time stamps.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
void setSynchedEvents(const SynchedEventList &e);
|
||||
|
||||
protected:
|
||||
|
@ -169,8 +168,8 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
EventTimingCodesFrame(const ByteVector &data, Header *h);
|
||||
EventTimingCodesFrame(const EventTimingCodesFrame &);
|
||||
EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
|
||||
|
@ -182,4 +181,5 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,12 +49,9 @@ class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB"),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate()) {
|
||||
}
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB"), d(new GeneralEncapsulatedObjectFramePrivate()) {}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate()) {
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data), d(new GeneralEncapsulatedObjectFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -63,6 +60,7 @@ GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame() {
|
|||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::toString() const {
|
||||
|
||||
String text = "[" + d->mimeType + "]";
|
||||
|
||||
if (!d->fileName.isEmpty())
|
||||
|
@ -72,6 +70,7 @@ String GeneralEncapsulatedObjectFrame::toString() const {
|
|||
text += " \"" + d->description + "\"";
|
||||
|
||||
return text;
|
||||
|
||||
}
|
||||
|
||||
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const {
|
||||
|
@ -119,6 +118,7 @@ void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
if (data.size() < 4) {
|
||||
debug("An object frame must contain at least 4 bytes.");
|
||||
return;
|
||||
|
@ -133,9 +133,11 @@ void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) {
|
|||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const {
|
||||
|
||||
StringList sl;
|
||||
sl.append(d->fileName);
|
||||
sl.append(d->description);
|
||||
|
@ -154,13 +156,13 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const {
|
|||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate()) {
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h), d(new GeneralEncapsulatedObjectFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -35,129 +35,128 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An ID3v2 general encapsulated object frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 general encapsulated objects.
|
||||
* 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
|
||||
* labelled with a content description (which may be blank), a required
|
||||
* mime-type, and a file name (may be blank). The content description
|
||||
* uniquely identifies the GEOB frame in the tag.
|
||||
*/
|
||||
* This is an implementation of ID3v2 general encapsulated objects.
|
||||
* 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 labelled with a content description (which may be blank),
|
||||
* a required mime-type, and a file name (may be blank).
|
||||
* The content description uniquely identifies the GEOB frame in the tag.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty object frame. The description, file name and text
|
||||
* encoding should be set manually.
|
||||
*/
|
||||
* Constructs an empty object frame.
|
||||
* The description, file name and text encoding should be set manually.
|
||||
*/
|
||||
GeneralEncapsulatedObjectFrame();
|
||||
|
||||
/*!
|
||||
* Constructs a GeneralEncapsulatedObjectFrame frame based on \a data.
|
||||
*
|
||||
* \warning This is \em not data for the encapsulated object, for that use
|
||||
* setObject(). This constructor is used when reading the frame from the
|
||||
* disk.
|
||||
*/
|
||||
* Constructs a GeneralEncapsulatedObjectFrame frame based on \a data.
|
||||
*
|
||||
* \warning This is \em not data for the encapsulated object, for that use
|
||||
* setObject().
|
||||
* This constructor is used when reading the frame from the disk.
|
||||
*/
|
||||
explicit GeneralEncapsulatedObjectFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the GeneralEncapsulatedObjectFrame instance.
|
||||
*/
|
||||
* Destroys the GeneralEncapsulatedObjectFrame instance.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding used for the description and file name.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
* Returns the text encoding used for the description and file name.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Set the text encoding used for the description and file name.
|
||||
*
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
* Set the text encoding used for the description and file name.
|
||||
*
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the object.
|
||||
*/
|
||||
* Returns the mime type of the object.
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the object.
|
||||
*/
|
||||
* Sets the mime type of the object.
|
||||
*/
|
||||
void setMimeType(const String &type);
|
||||
|
||||
/*!
|
||||
* Returns the file name of the object.
|
||||
*
|
||||
* \see setFileName()
|
||||
*/
|
||||
* Returns the file name of the object.
|
||||
*
|
||||
* \see setFileName()
|
||||
*/
|
||||
String fileName() const;
|
||||
|
||||
/*!
|
||||
* Sets the file name for the object.
|
||||
*
|
||||
* \see fileName()
|
||||
*/
|
||||
* Sets the file name for the object.
|
||||
*
|
||||
* \see fileName()
|
||||
*/
|
||||
void setFileName(const String &name);
|
||||
|
||||
/*!
|
||||
* Returns the content description of the object.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
* Returns the content description of the object.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the content description of the object to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
* Sets the content description of the object to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the object data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setObject()
|
||||
* \see mimeType()
|
||||
*/
|
||||
* Returns the object data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setObject()
|
||||
* \see mimeType()
|
||||
*/
|
||||
ByteVector object() const;
|
||||
|
||||
/*!
|
||||
* Sets the object data to \a data. \a data should be of the type specified in
|
||||
* this frame's mime-type specification.
|
||||
*
|
||||
* \see object()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
* Sets the object data to \a data.
|
||||
* \a data should be of the type specified in this frame's mime-type specification.
|
||||
*
|
||||
* \see object()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setObject(const ByteVector &object);
|
||||
|
||||
protected:
|
||||
|
@ -172,6 +171,7 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
|
|||
class GeneralEncapsulatedObjectFramePrivate;
|
||||
GeneralEncapsulatedObjectFramePrivate *d;
|
||||
};
|
||||
|
||||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -44,13 +44,11 @@ class OwnershipFrame::OwnershipFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE"),
|
||||
d(new OwnershipFramePrivate()) {
|
||||
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE"),d(new OwnershipFramePrivate()) {
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data),
|
||||
d(new OwnershipFramePrivate()) {
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data),d(new OwnershipFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -99,6 +97,7 @@ void OwnershipFrame::setTextEncoding(String::Type encoding) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OwnershipFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
int pos = 0;
|
||||
|
||||
// Get the text encoding
|
||||
|
@ -123,9 +122,11 @@ void OwnershipFrame::parseFields(const ByteVector &data) {
|
|||
d->seller = Tag::latin1StringHandler()->parse(data.mid(pos));
|
||||
else
|
||||
d->seller = String(data.mid(pos), d->textEncoding);
|
||||
|
||||
}
|
||||
|
||||
ByteVector OwnershipFrame::renderFields() const {
|
||||
|
||||
StringList sl;
|
||||
sl.append(d->seller);
|
||||
|
||||
|
@ -140,13 +141,13 @@ ByteVector OwnershipFrame::renderFields() const {
|
|||
v.append(d->seller.data(encoding));
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new OwnershipFramePrivate()) {
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h), d(new OwnershipFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -31,101 +31,98 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 "ownership"
|
||||
|
||||
/*!
|
||||
* This implements the ID3v2 ownership (OWNE frame). It consists of
|
||||
* a price paid, a date purchased (YYYYMMDD) and the name of the seller.
|
||||
*/
|
||||
* This implements the ID3v2 ownership (OWNE frame).
|
||||
* It consists of a price paid, a date purchased (YYYYMMDD) and the name of the seller.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT OwnershipFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty ownership frame.
|
||||
*/
|
||||
* Construct an empty ownership frame.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this OwnershipFrame instance.
|
||||
*/
|
||||
* Destroys this OwnershipFrame instance.
|
||||
*/
|
||||
virtual ~OwnershipFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the date purchased.
|
||||
*
|
||||
* \see setDatePurchased()
|
||||
*/
|
||||
* Returns the date purchased.
|
||||
*
|
||||
* \see setDatePurchased()
|
||||
*/
|
||||
String datePurchased() const;
|
||||
|
||||
/*!
|
||||
* Set the date purchased.
|
||||
*
|
||||
* \see datePurchased()
|
||||
*/
|
||||
* Set the date purchased.
|
||||
*
|
||||
* \see datePurchased()
|
||||
*/
|
||||
void setDatePurchased(const String &datePurchased);
|
||||
|
||||
/*!
|
||||
* Returns the price paid.
|
||||
*
|
||||
* \see setPricePaid()
|
||||
*/
|
||||
* Returns the price paid.
|
||||
*
|
||||
* \see setPricePaid()
|
||||
*/
|
||||
String pricePaid() const;
|
||||
|
||||
/*!
|
||||
* Set the price paid.
|
||||
*
|
||||
* \see pricePaid()
|
||||
*/
|
||||
* Set the price paid.
|
||||
*
|
||||
* \see pricePaid()
|
||||
*/
|
||||
void setPricePaid(const String &pricePaid);
|
||||
|
||||
/*!
|
||||
* Returns the seller.
|
||||
*
|
||||
* \see setSeller()
|
||||
*/
|
||||
* Returns the seller.
|
||||
*
|
||||
* \see setSeller()
|
||||
*/
|
||||
String seller() const;
|
||||
|
||||
/*!
|
||||
* Set the seller.
|
||||
*
|
||||
* \see seller()
|
||||
*/
|
||||
* Set the seller.
|
||||
*
|
||||
* \see seller()
|
||||
*/
|
||||
void setSeller(const String &seller);
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Sets the text encoding to be used when rendering this frame to \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
protected:
|
||||
|
@ -136,8 +133,8 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
OwnershipFrame(const ByteVector &data, Header *h);
|
||||
OwnershipFrame(const OwnershipFrame &);
|
||||
OwnershipFrame &operator=(const OwnershipFrame &);
|
||||
|
@ -149,4 +146,5 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,8 +37,7 @@ class PodcastFrame::PodcastFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PodcastFrame::PodcastFrame() : Frame("PCST"),
|
||||
d(new PodcastFramePrivate()) {
|
||||
PodcastFrame::PodcastFrame() : Frame("PCST"), d(new PodcastFramePrivate()) {
|
||||
d->fieldData = ByteVector(4, '\0');
|
||||
}
|
||||
|
||||
|
@ -66,7 +65,6 @@ ByteVector PodcastFrame::renderFields() const {
|
|||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new PodcastFramePrivate()) {
|
||||
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h), d(new PodcastFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -31,30 +31,29 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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 {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct a podcast frame.
|
||||
*/
|
||||
* Construct a podcast frame.
|
||||
*/
|
||||
PodcastFrame();
|
||||
|
||||
/*!
|
||||
* Destroys this PodcastFrame instance.
|
||||
*/
|
||||
* Destroys this PodcastFrame instance.
|
||||
*/
|
||||
virtual ~PodcastFrame();
|
||||
|
||||
/*!
|
||||
* Returns a null string.
|
||||
*/
|
||||
* Returns a null string.
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
protected:
|
||||
|
@ -65,8 +64,8 @@ class TAGLIB_EXPORT PodcastFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PodcastFrame(const ByteVector &data, Header *h);
|
||||
PodcastFrame(const PodcastFrame &);
|
||||
PodcastFrame &operator=(const PodcastFrame &);
|
||||
|
@ -78,4 +77,5 @@ class TAGLIB_EXPORT PodcastFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,12 +42,9 @@ class PopularimeterFrame::PopularimeterFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame() : Frame("POPM"),
|
||||
d(new PopularimeterFramePrivate()) {
|
||||
}
|
||||
PopularimeterFrame::PopularimeterFrame() : Frame("POPM"), d(new PopularimeterFramePrivate()) {}
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data),
|
||||
d(new PopularimeterFramePrivate()) {
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data), d(new PopularimeterFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -88,6 +85,7 @@ void PopularimeterFrame::setCounter(unsigned int s) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PopularimeterFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
int pos = 0, size = int(data.size());
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector PopularimeterFrame::renderFields() const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->email.data(String::Latin1));
|
||||
|
@ -111,13 +111,13 @@ ByteVector PopularimeterFrame::renderFields() const {
|
|||
data.append(ByteVector::fromUInt(d->counter));
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new PopularimeterFramePrivate()) {
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h), d(new PopularimeterFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -31,82 +31,81 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 "popularimeter"
|
||||
|
||||
/*!
|
||||
* This implements the ID3v2 popularimeter (POPM frame). It consists of
|
||||
* an email, a rating and an optional counter.
|
||||
*/
|
||||
* This implements the ID3v2 popularimeter (POPM frame).
|
||||
* It consists of an email, a rating and an optional counter.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT PopularimeterFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty popularimeter frame.
|
||||
*/
|
||||
* Construct an empty popularimeter frame.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this PopularimeterFrame instance.
|
||||
*/
|
||||
* Destroys this PopularimeterFrame instance.
|
||||
*/
|
||||
virtual ~PopularimeterFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the email.
|
||||
*
|
||||
* \see setEmail()
|
||||
*/
|
||||
* Returns the email.
|
||||
*
|
||||
* \see setEmail()
|
||||
*/
|
||||
String email() const;
|
||||
|
||||
/*!
|
||||
* Set the email.
|
||||
*
|
||||
* \see email()
|
||||
*/
|
||||
* Set the email.
|
||||
*
|
||||
* \see email()
|
||||
*/
|
||||
void setEmail(const String &email);
|
||||
|
||||
/*!
|
||||
* Returns the rating.
|
||||
*
|
||||
* \see setRating()
|
||||
*/
|
||||
* Returns the rating.
|
||||
*
|
||||
* \see setRating()
|
||||
*/
|
||||
int rating() const;
|
||||
|
||||
/*!
|
||||
* Set the rating.
|
||||
*
|
||||
* \see rating()
|
||||
*/
|
||||
* Set the rating.
|
||||
*
|
||||
* \see rating()
|
||||
*/
|
||||
void setRating(int rating);
|
||||
|
||||
/*!
|
||||
* Returns the counter.
|
||||
*
|
||||
* \see setCounter()
|
||||
*/
|
||||
* Returns the counter.
|
||||
*
|
||||
* \see setCounter()
|
||||
*/
|
||||
unsigned int counter() const;
|
||||
|
||||
/*!
|
||||
* Set the counter.
|
||||
*
|
||||
* \see counter()
|
||||
*/
|
||||
* Set the counter.
|
||||
*
|
||||
* \see counter()
|
||||
*/
|
||||
void setCounter(unsigned int counter);
|
||||
|
||||
protected:
|
||||
|
@ -117,8 +116,8 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PopularimeterFrame(const ByteVector &data, Header *h);
|
||||
PopularimeterFrame(const PopularimeterFrame &);
|
||||
PopularimeterFrame &operator=(const PopularimeterFrame &);
|
||||
|
@ -130,4 +129,5 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,12 +44,9 @@ class PrivateFrame::PrivateFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame() : Frame("PRIV"),
|
||||
d(new PrivateFramePrivate()) {
|
||||
}
|
||||
PrivateFrame::PrivateFrame() : Frame("PRIV"), d(new PrivateFramePrivate()) {}
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data),
|
||||
d(new PrivateFramePrivate()) {
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data), d(new PrivateFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -82,6 +79,7 @@ void PrivateFrame::setData(const ByteVector &data) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PrivateFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
if (data.size() < 2) {
|
||||
debug("A private frame must contain at least 2 bytes.");
|
||||
return;
|
||||
|
@ -94,9 +92,11 @@ void PrivateFrame::parseFields(const ByteVector &data) {
|
|||
|
||||
d->owner = String(data.mid(0, endOfOwner));
|
||||
d->data = data.mid(endOfOwner + 1);
|
||||
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::renderFields() const {
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(d->owner.data(String::Latin1));
|
||||
|
@ -104,13 +104,13 @@ ByteVector PrivateFrame::renderFields() const {
|
|||
v.append(d->data);
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new PrivateFramePrivate()) {
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h), d(new PrivateFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 privateframe
|
||||
|
@ -42,49 +41,49 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
|
|||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty private frame.
|
||||
*/
|
||||
* Construct an empty private frame.
|
||||
*/
|
||||
PrivateFrame();
|
||||
|
||||
/*!
|
||||
* Construct a private frame based on the data in \a data.
|
||||
*
|
||||
* \note This is the constructor used when parsing the frame from a file.
|
||||
*/
|
||||
* Construct a private frame based on the data in \a data.
|
||||
*
|
||||
* \note This is the constructor used when parsing the frame from a file.
|
||||
*/
|
||||
explicit PrivateFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this private frame instance.
|
||||
*/
|
||||
* Destroys this private frame instance.
|
||||
*/
|
||||
virtual ~PrivateFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this private frame, currently just the owner.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Returns the text of this private frame, currently just the owner.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* \return The owner of the private frame.
|
||||
* \note This should contain an email address or link to a website.
|
||||
*/
|
||||
* \return The owner of the private frame.
|
||||
* \note This should contain an email address or link to a website.
|
||||
*/
|
||||
String owner() const;
|
||||
|
||||
/*!
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
/*!
|
||||
* Sets the owner of the frame to \a s.
|
||||
* \note This should contain an email address or link to a website.
|
||||
*/
|
||||
* Sets the owner of the frame to \a s.
|
||||
* \note This should contain an email address or link to a website.
|
||||
*/
|
||||
void setOwner(const String &s);
|
||||
|
||||
/*!
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
void setData(const ByteVector &v);
|
||||
|
||||
protected:
|
||||
|
@ -95,8 +94,8 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PrivateFrame(const ByteVector &data, Header *h);
|
||||
|
||||
PrivateFrame(const PrivateFrame &);
|
||||
|
@ -109,4 +108,5 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,12 +49,9 @@ class RelativeVolumeFrame::RelativeVolumeFramePrivate {
|
|||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2"),
|
||||
d(new RelativeVolumeFramePrivate()) {
|
||||
}
|
||||
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2"), d(new RelativeVolumeFramePrivate()) {}
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data),
|
||||
d(new RelativeVolumeFramePrivate()) {
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data), d(new RelativeVolumeFramePrivate()) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
|
@ -67,6 +64,7 @@ String RelativeVolumeFrame::toString() const {
|
|||
}
|
||||
|
||||
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const {
|
||||
|
||||
List<ChannelType> l;
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
|
@ -74,17 +72,7 @@ List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const {
|
|||
l.append((*it).first);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const {
|
||||
return MasterVolume;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
void RelativeVolumeFrame::setChannelType(ChannelType) {
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const {
|
||||
|
@ -148,6 +136,7 @@ void RelativeVolumeFrame::setIdentification(const String &s) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RelativeVolumeFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
int pos = 0;
|
||||
d->identification = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
|
@ -170,9 +159,11 @@ void RelativeVolumeFrame::parseFields(const ByteVector &data) {
|
|||
channel.peakVolume.peakVolume = data.mid(pos, bytes);
|
||||
pos += bytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector RelativeVolumeFrame::renderFields() const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->identification.data(String::Latin1));
|
||||
|
@ -191,13 +182,13 @@ ByteVector RelativeVolumeFrame::renderFields() const {
|
|||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new RelativeVolumeFramePrivate()) {
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h), d(new RelativeVolumeFramePrivate()) {
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -32,28 +32,24 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An ID3v2 relative volume adjustment frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 relative volume adjustment. 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.
|
||||
*
|
||||
* Multiple relative volume adjustment frames may be present in the tag
|
||||
* each with a unique identification and describing volume adjustment for
|
||||
* different channel types.
|
||||
*/
|
||||
* This is an implementation of ID3v2 relative volume adjustment.
|
||||
* 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.
|
||||
*
|
||||
* 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 {
|
||||
friend class FrameFactory;
|
||||
|
||||
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 {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
|
@ -78,149 +74,125 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
|
|||
//! 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
|
||||
* a block of bytes. These two values should always be updated in tandem.
|
||||
*/
|
||||
* The peak volume is described as a series of bits that is padded to fill a block of bytes.
|
||||
* These two values should always be updated in tandem.
|
||||
*/
|
||||
struct PeakVolume {
|
||||
/*!
|
||||
* Constructs an empty peak volume description.
|
||||
*/
|
||||
* Constructs an empty peak volume description.
|
||||
*/
|
||||
PeakVolume() : bitsRepresentingPeak(0) {}
|
||||
/*!
|
||||
* The number of bits (in the range of 0 to 255) used to describe the
|
||||
* peak volume.
|
||||
*/
|
||||
* The number of bits (in the range of 0 to 255) used to describe the peak volume.
|
||||
*/
|
||||
unsigned char bitsRepresentingPeak;
|
||||
/*!
|
||||
* The array of bits (represented as a series of bytes) used to describe
|
||||
* the peak volume.
|
||||
*/
|
||||
* The array of bits (represented as a series of bytes) used to describe the peak volume.
|
||||
*/
|
||||
ByteVector peakVolume;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs a RelativeVolumeFrame. The relevant data should be set
|
||||
* manually.
|
||||
*/
|
||||
* Constructs a RelativeVolumeFrame. The relevant data should be set manually.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys the RelativeVolumeFrame instance.
|
||||
*/
|
||||
* Destroys the RelativeVolumeFrame instance.
|
||||
*/
|
||||
virtual ~RelativeVolumeFrame();
|
||||
|
||||
/*!
|
||||
* Returns the frame's identification.
|
||||
*
|
||||
* \see identification()
|
||||
*/
|
||||
* Returns the frame's identification.
|
||||
*
|
||||
* \see identification()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* \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
|
||||
* the way it appears below for binary compatibility reasons, let's at
|
||||
* least pretend that it looks clean.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/*!
|
||||
* Returns the relative volume adjustment "index". As indicated by the
|
||||
* ID3v2 standard this is a 16-bit signed integer that reflects the
|
||||
* 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.
|
||||
*
|
||||
* \see setVolumeAdjustmentIndex()
|
||||
* \see volumeAjustment()
|
||||
*/
|
||||
* Returns the relative volume adjustment "index".
|
||||
* As indicated by the ID3v2 standard this is a 16-bit signed integer that reflects the 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.
|
||||
*
|
||||
* \see setVolumeAdjustmentIndex()
|
||||
* \see volumeAjustment()
|
||||
*/
|
||||
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
|
||||
|
||||
/*!
|
||||
* Set the volume adjustment to \a index. As indicated by the ID3v2
|
||||
* standard this is a 16-bit signed integer that reflects the decibels of
|
||||
* adjustment when divided by 512.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see volumeAdjustmentIndex()
|
||||
* \see setVolumeAjustment()
|
||||
*/
|
||||
* Set the volume adjustment to \a index.
|
||||
* As indicated by the ID3v2 standard this is a 16-bit signed integer that reflects the decibels of adjustment when divided by 512.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see volumeAdjustmentIndex()
|
||||
* \see setVolumeAjustment()
|
||||
*/
|
||||
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);
|
||||
|
||||
/*!
|
||||
* Returns the relative volume adjustment in decibels.
|
||||
*
|
||||
* \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 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.
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
* Returns the relative volume adjustment in decibels.
|
||||
*
|
||||
* \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 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.
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
float volumeAdjustment(ChannelType type = MasterVolume) const;
|
||||
|
||||
/*!
|
||||
* Set the relative volume adjustment in decibels to \a adjustment.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \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().
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
* Set the relative volume adjustment in decibels to \a adjustment.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \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().
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume);
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setPeakVolume()
|
||||
*/
|
||||
* 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 available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setPeakVolume()
|
||||
*/
|
||||
PeakVolume peakVolume(ChannelType type = MasterVolume) const;
|
||||
|
||||
/*!
|
||||
* Sets the peak volume to \a peak.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see peakVolume()
|
||||
*/
|
||||
* Sets the peak volume to \a peak.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see peakVolume()
|
||||
*/
|
||||
void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume);
|
||||
|
||||
#else
|
||||
|
||||
// BIC: Combine each of the following pairs of functions (or maybe just
|
||||
// rework this junk altogether).
|
||||
// BIC: Combine each of the following pairs of functions (or maybe just rework this junk altogether).
|
||||
|
||||
short volumeAdjustmentIndex(ChannelType type) const;
|
||||
short volumeAdjustmentIndex() const;
|
||||
|
@ -243,15 +215,14 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
|
|||
#endif
|
||||
|
||||
/*!
|
||||
* Returns the identification for this frame.
|
||||
*/
|
||||
* Returns the identification for this frame.
|
||||
*/
|
||||
String identification() const;
|
||||
|
||||
/*!
|
||||
* Sets the identification of the frame to \a s. The string
|
||||
* is used to identify the situation and/or device where this
|
||||
* adjustment should apply.
|
||||
*/
|
||||
* Sets the identification of the frame to \a s.
|
||||
* The string is used to identify the situation and/or device where this adjustment should apply.
|
||||
*/
|
||||
void setIdentification(const String &s);
|
||||
|
||||
protected:
|
||||
|
@ -270,4 +241,5 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -123,6 +123,7 @@ void SynchronizedLyricsFrame::setSynchedText(
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SynchronizedLyricsFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
const int end = data.size();
|
||||
if (end < 7) {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector SynchronizedLyricsFrame::renderFields() const {
|
||||
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = d->textEncoding;
|
||||
|
@ -207,6 +210,7 @@ ByteVector SynchronizedLyricsFrame::renderFields() const {
|
|||
}
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -31,20 +31,19 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 synchronized lyrics frame
|
||||
/*!
|
||||
* An implementation of ID3v2 synchronized lyrics.
|
||||
*/
|
||||
* An implementation of ID3v2 synchronized lyrics.
|
||||
*/
|
||||
class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Specifies the timestamp format used.
|
||||
*/
|
||||
* Specifies the timestamp format used.
|
||||
*/
|
||||
enum TimestampFormat {
|
||||
//! The timestamp is of unknown format.
|
||||
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 {
|
||||
//! The text is some other type of text.
|
||||
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 {
|
||||
SynchedText(unsigned int ms, String str) : time(ms), text(str) {}
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Construct an empty synchronized lyrics frame that will use the text
|
||||
* encoding \a encoding.
|
||||
*/
|
||||
* Construct an empty synchronized lyrics frame that will use the text encoding \a encoding.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this SynchronizedLyricsFrame instance.
|
||||
*/
|
||||
* Destroys this SynchronizedLyricsFrame instance.
|
||||
*/
|
||||
virtual ~SynchronizedLyricsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the description of this synchronized lyrics frame.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
* Returns the description of this synchronized lyrics frame.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* 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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
* 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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the timestamp format.
|
||||
*/
|
||||
* Returns the timestamp format.
|
||||
*/
|
||||
TimestampFormat timestampFormat() const;
|
||||
|
||||
/*!
|
||||
* Returns the type of text contained.
|
||||
*/
|
||||
* Returns the type of text contained.
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this synchronized lyrics frame.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
* Returns the description of this synchronized lyrics frame.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text with the time stamps.
|
||||
*/
|
||||
* Returns the text with the time stamps.
|
||||
*/
|
||||
SynchedTextList synchedText() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Sets the text encoding to be used when rendering this frame to \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* 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 languageCode.
|
||||
*
|
||||
* \see language()
|
||||
*/
|
||||
* 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 languageCode.
|
||||
*
|
||||
* \see language()
|
||||
*/
|
||||
void setLanguage(const ByteVector &languageCode);
|
||||
|
||||
/*!
|
||||
* Set the timestamp format.
|
||||
*
|
||||
* \see timestampFormat()
|
||||
*/
|
||||
* Set the timestamp format.
|
||||
*
|
||||
* \see timestampFormat()
|
||||
*/
|
||||
void setTimestampFormat(TimestampFormat f);
|
||||
|
||||
/*!
|
||||
* Set the type of text contained.
|
||||
*
|
||||
* \see type()
|
||||
*/
|
||||
* Set the type of text contained.
|
||||
*
|
||||
* \see type()
|
||||
*/
|
||||
void setType(Type t);
|
||||
|
||||
/*!
|
||||
* Sets the description of the synchronized lyrics frame to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
* Sets the description of the synchronized lyrics frame to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the text with the time stamps.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
* Sets the text with the time stamps.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
void setSynchedText(const SynchedTextList &t);
|
||||
|
||||
protected:
|
||||
|
@ -215,8 +210,8 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
|
|||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
SynchronizedLyricsFrame(const ByteVector &data, Header *h);
|
||||
SynchronizedLyricsFrame(const SynchronizedLyricsFrame &);
|
||||
SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &);
|
||||
|
@ -228,4 +223,5 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,9 +34,7 @@ using namespace ID3v2;
|
|||
|
||||
class TableOfContentsFrame::TableOfContentsFramePrivate {
|
||||
public:
|
||||
TableOfContentsFramePrivate() : tagHeader(0),
|
||||
isTopLevel(false),
|
||||
isOrdered(false) {
|
||||
TableOfContentsFramePrivate() : tagHeader(nullptr), isTopLevel(false), isOrdered(false) {
|
||||
embeddedFrameList.setAutoDelete(true);
|
||||
}
|
||||
|
||||
|
@ -69,6 +67,7 @@ ByteVectorList &strip(ByteVectorList &l) {
|
|||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -81,16 +80,15 @@ TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const
|
|||
setData(data);
|
||||
}
|
||||
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID,
|
||||
const ByteVectorList &children,
|
||||
const FrameList &embeddedFrames) : ID3v2::Frame("CTOC"),
|
||||
d(new TableOfContentsFramePrivate()) {
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID, const ByteVectorList &children, const FrameList &embeddedFrames) : ID3v2::Frame("CTOC"), d(new TableOfContentsFramePrivate()) {
|
||||
|
||||
d->elementID = elementID;
|
||||
strip(d->elementID);
|
||||
d->childElements = children;
|
||||
|
||||
for (FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
|
||||
addEmbeddedFrame(*it);
|
||||
|
||||
}
|
||||
|
||||
TableOfContentsFrame::~TableOfContentsFrame() {
|
||||
|
@ -167,6 +165,7 @@ void TableOfContentsFrame::addEmbeddedFrame(Frame *frame) {
|
|||
}
|
||||
|
||||
void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del) {
|
||||
|
||||
// remove the frame from the frame list
|
||||
FrameList::Iterator it = d->embeddedFrameList.find(frame);
|
||||
d->embeddedFrameList.erase(it);
|
||||
|
@ -178,15 +177,19 @@ void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del) {
|
|||
// ...and delete as desired
|
||||
if (del)
|
||||
delete frame;
|
||||
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id) {
|
||||
|
||||
FrameList l = d->embeddedFrameListMap[id];
|
||||
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeEmbeddedFrame(*it, true);
|
||||
|
||||
}
|
||||
|
||||
String TableOfContentsFrame::toString() const {
|
||||
|
||||
String s = String(d->elementID) +
|
||||
": top level: " + (d->isTopLevel ? "true" : "false") +
|
||||
", ordered: " + (d->isOrdered ? "true" : "false");
|
||||
|
@ -205,19 +208,21 @@ String TableOfContentsFrame::toString() const {
|
|||
}
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
PropertyMap TableOfContentsFrame::asProperties() const {
|
||||
|
||||
PropertyMap map;
|
||||
|
||||
map.unsupportedData().append(frameID() + String("/") + d->elementID);
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag,
|
||||
const ByteVector &eID) // static
|
||||
{
|
||||
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) { // static
|
||||
|
||||
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
|
||||
|
||||
for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
|
||||
|
@ -229,10 +234,11 @@ TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *ta
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static
|
||||
{
|
||||
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) { // static
|
||||
|
||||
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
|
||||
|
||||
for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
|
||||
|
@ -244,9 +250,11 @@ TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag)
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
unsigned int size = data.size();
|
||||
if (size < 6) {
|
||||
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();
|
||||
addEmbeddedFrame(frame);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector TableOfContentsFrame::renderFields() const {
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->elementID);
|
||||
|
@ -311,11 +321,10 @@ ByteVector TableOfContentsFrame::renderFields() const {
|
|||
data.append((*it2)->render());
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
|
||||
const ByteVector &data, Header *h) : Frame(h),
|
||||
d(new TableOfContentsFramePrivate()) {
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h), d(new TableOfContentsFramePrivate()) {
|
||||
d->tagHeader = tagHeader;
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
|
|
@ -33,13 +33,12 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 table of contents frames. Purpose
|
||||
* of this frame is to allow a table of contents to be defined.
|
||||
*/
|
||||
* This is an implementation of ID3v2 table of contents frames.
|
||||
* Purpose of this frame is to allow a table of contents to be defined.
|
||||
*/
|
||||
|
||||
//! An implementation of ID3v2 table of contents frames
|
||||
|
||||
|
@ -48,176 +47,159 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
|
|||
|
||||
public:
|
||||
/*!
|
||||
* Creates a table of contents frame based on \a data. \a tagHeader is
|
||||
* required as the internal frames are parsed based on the tag version.
|
||||
*/
|
||||
* Creates a table of contents frame based on \a data.
|
||||
* \a tagHeader is required as the internal frames are parsed based on the tag version.
|
||||
*/
|
||||
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Creates a table of contents frame with the element ID \a elementID,
|
||||
* the child elements \a children and embedded frames, which become owned
|
||||
* by this frame, in \a embeddedFrames.
|
||||
*/
|
||||
* Creates a table of contents frame with the element ID \a elementID,
|
||||
* the child elements \a children and embedded frames, which become owned by this frame, in \a embeddedFrames.
|
||||
*/
|
||||
TableOfContentsFrame(const ByteVector &elementID,
|
||||
const ByteVectorList &children = ByteVectorList(),
|
||||
const FrameList &embeddedFrames = FrameList());
|
||||
|
||||
/*!
|
||||
* Destroys the frame.
|
||||
*/
|
||||
* Destroys the frame.
|
||||
*/
|
||||
~TableOfContentsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the elementID of the frame. Element ID
|
||||
* is a null terminated string, however it's not human-readable.
|
||||
*
|
||||
* \see setElementID()
|
||||
*/
|
||||
* Returns the elementID of the frame.
|
||||
* Element ID is a null terminated string, however it's not human-readable.
|
||||
*
|
||||
* \see setElementID()
|
||||
*/
|
||||
ByteVector elementID() const;
|
||||
|
||||
/*!
|
||||
* Returns true, if the frame is top-level (doesn't have
|
||||
* any parent CTOC frame).
|
||||
*
|
||||
* \see setIsTopLevel()
|
||||
*/
|
||||
* Returns true, if the frame is top-level (doesn't have any parent CTOC frame).
|
||||
*
|
||||
* \see setIsTopLevel()
|
||||
*/
|
||||
bool isTopLevel() const;
|
||||
|
||||
/*!
|
||||
* Returns true, if the child elements list entries
|
||||
* are ordered.
|
||||
*
|
||||
* \see setIsOrdered()
|
||||
*/
|
||||
* Returns true, if the child elements list entries are ordered.
|
||||
*
|
||||
* \see setIsOrdered()
|
||||
*/
|
||||
bool isOrdered() const;
|
||||
|
||||
/*!
|
||||
* Returns count of child elements of the frame. It always
|
||||
* corresponds to size of child elements list.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
* Returns count of child elements of the frame. It always corresponds to size of child elements list.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
unsigned int entryCount() const;
|
||||
|
||||
/*!
|
||||
* Returns list of child elements of the frame.
|
||||
*
|
||||
* \see setChildElements()
|
||||
*/
|
||||
* Returns list of child elements of the frame.
|
||||
*
|
||||
* \see setChildElements()
|
||||
*/
|
||||
ByteVectorList childElements() const;
|
||||
|
||||
/*!
|
||||
* Sets the elementID of the frame to \a eID. If \a eID isn't
|
||||
* null terminated, a null char is appended automatically.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
* Sets the elementID of the frame to \a eID. If \a eID isn't null terminated, a null char is appended automatically.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
void setElementID(const ByteVector &eID);
|
||||
|
||||
/*!
|
||||
* Sets, if the frame is top-level (doesn't have
|
||||
* any parent CTOC frame).
|
||||
*
|
||||
* \see isTopLevel()
|
||||
*/
|
||||
* Sets, if the frame is top-level (doesn't have any parent CTOC frame).
|
||||
*
|
||||
* \see isTopLevel()
|
||||
*/
|
||||
void setIsTopLevel(const bool &t);
|
||||
|
||||
/*!
|
||||
* Sets, if the child elements list entries
|
||||
* are ordered.
|
||||
*
|
||||
* \see isOrdered()
|
||||
*/
|
||||
* Sets, if the child elements list entries are ordered.
|
||||
*
|
||||
* \see isOrdered()
|
||||
*/
|
||||
void setIsOrdered(const bool &o);
|
||||
|
||||
/*!
|
||||
* Sets list of child elements of the frame to \a l.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
* Sets list of child elements of the frame to \a l.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
void setChildElements(const ByteVectorList &l);
|
||||
|
||||
/*!
|
||||
* Adds \a cE to list of child elements of the frame.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
* Adds \a cE to list of child elements of the frame.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
void addChildElement(const ByteVector &cE);
|
||||
|
||||
/*!
|
||||
* Removes \a cE to list of child elements of the frame.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
* Removes \a cE to list of child elements of the frame.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
void removeChildElement(const ByteVector &cE);
|
||||
|
||||
/*!
|
||||
* Returns a reference to the frame list map. 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
|
||||
* embedded frames. Many frame types allow multiple instances of the same
|
||||
* frame type so this is a map of lists. In most cases however there will
|
||||
* only be a single frame of a certain type.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*
|
||||
* \see embeddedFrameList()
|
||||
*/
|
||||
* Returns a reference to the frame list map.
|
||||
* 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 embedded frames.
|
||||
* Many frame types allow multiple instances of the same frame type so this is a map of lists.
|
||||
* In most cases however there will only be a single frame of a certain type.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*
|
||||
* \see embeddedFrameList()
|
||||
*/
|
||||
const FrameListMap &embeddedFrameListMap() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the embedded frame list. This is an FrameList
|
||||
* of all of the frames embedded in the CTOC frame in the order that they
|
||||
* 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.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*/
|
||||
* Returns a reference to the embedded frame list.
|
||||
* This is an FrameList of all of the frames embedded in the CTOC frame in the order that they 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.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*/
|
||||
const FrameList &embeddedFrameList() const;
|
||||
|
||||
/*!
|
||||
* 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. This
|
||||
* is just a convenience and is equivalent to:
|
||||
*
|
||||
* \code
|
||||
* embeddedFrameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see embeddedFrameListMap()
|
||||
*/
|
||||
* 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.
|
||||
* This is just a convenience and is equivalent to:
|
||||
*
|
||||
* \code
|
||||
* embeddedFrameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see embeddedFrameListMap()
|
||||
*/
|
||||
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
|
||||
|
||||
/*!
|
||||
* Add an embedded frame to the CTOC frame. 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
|
||||
* returned by embeddedFrameList()
|
||||
*/
|
||||
* Add an embedded frame to the CTOC frame.
|
||||
* 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 returned by embeddedFrameList()
|
||||
*/
|
||||
void addEmbeddedFrame(Frame *frame);
|
||||
|
||||
/*!
|
||||
* Remove an embedded frame from the CTOC frame. 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
|
||||
* returned by embeddedFrameList()
|
||||
*/
|
||||
* Remove an embedded frame from the CTOC frame.
|
||||
* 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 returned by embeddedFrameList()
|
||||
*/
|
||||
void removeEmbeddedFrame(Frame *frame, bool del = true);
|
||||
|
||||
/*!
|
||||
* Remove all embedded frames of type \a id from the CTOC frame and free their
|
||||
* memory.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list
|
||||
* returned by embeddedFrameList()
|
||||
*/
|
||||
* Remove all embedded frames of type \a id from the CTOC frame and free their memory.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
|
||||
*/
|
||||
void removeEmbeddedFrames(const ByteVector &id);
|
||||
|
||||
virtual String toString() const;
|
||||
|
@ -225,21 +207,21 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
|
|||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* CTOC frames each have a unique element ID. This searches for a CTOC
|
||||
* frame with the element ID \a eID and returns a pointer to it. This
|
||||
* can be used to link together parent and child CTOC frames.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
* CTOC frames each have a unique element ID.
|
||||
* This searches for a CTOC frame with the element ID \a eID and returns a pointer to it.
|
||||
* This can be used to link together parent and child CTOC frames.
|
||||
*
|
||||
* \see elementID()
|
||||
*/
|
||||
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
|
||||
* any frame, which contains this frame in its child elements list). Only a single frame
|
||||
* within tag can be top-level. This searches for a top-level CTOC frame.
|
||||
*
|
||||
* \see isTopLevel()
|
||||
*/
|
||||
* CTOC frames each contain a flag that indicates,
|
||||
* if CTOC frame is top-level (there isn't any frame, which contains this frame in its child elements list).
|
||||
* Only a single frame within tag can be top-level. This searches for a top-level CTOC frame.
|
||||
*
|
||||
* \see isTopLevel()
|
||||
*/
|
||||
static TableOfContentsFrame *findTopLevel(const Tag *tag);
|
||||
|
||||
protected:
|
||||
|
@ -254,6 +236,7 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
|
|||
class TableOfContentsFramePrivate;
|
||||
TableOfContentsFramePrivate *d;
|
||||
};
|
||||
|
||||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
|
|
@ -53,8 +53,8 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : Frame
|
|||
setData(data);
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) { // static
|
||||
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
|
||||
StringList l;
|
||||
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
|
||||
|
@ -63,10 +63,11 @@ TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const Property
|
|||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) { // static
|
||||
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL");
|
||||
StringList l;
|
||||
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
|
||||
|
@ -77,6 +78,7 @@ TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const Property
|
|||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
|
||||
}
|
||||
|
||||
TextIdentificationFrame::~TextIdentificationFrame() {
|
||||
|
@ -119,17 +121,19 @@ const char *involvedPeople[][2] = {
|
|||
const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]);
|
||||
} // namespace
|
||||
|
||||
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
|
||||
{
|
||||
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() { // static
|
||||
|
||||
static KeyConversionMap m;
|
||||
if (m.isEmpty()) {
|
||||
for (size_t i = 0; i < involvedPeopleSize; ++i)
|
||||
m.insert(involvedPeople[i][1], involvedPeople[i][0]);
|
||||
}
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::asProperties() const {
|
||||
|
||||
if (frameID() == "TIPL")
|
||||
return makeTIPLProperties();
|
||||
if (frameID() == "TMCL")
|
||||
|
@ -163,6 +167,7 @@ PropertyMap TextIdentificationFrame::asProperties() const {
|
|||
PropertyMap ret;
|
||||
ret.insert(tagName, values);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -170,6 +175,7 @@ PropertyMap TextIdentificationFrame::asProperties() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TextIdentificationFrame::parseFields(const ByteVector &data) {
|
||||
|
||||
// Don't try to parse invalid frames
|
||||
|
||||
if (data.size() < 2)
|
||||
|
@ -209,9 +215,11 @@ void TextIdentificationFrame::parseFields(const ByteVector &data) {
|
|||
d->fieldList.append(String(*it, d->textEncoding));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ByteVector TextIdentificationFrame::renderFields() const {
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
@ -231,6 +239,7 @@ ByteVector TextIdentificationFrame::renderFields() const {
|
|||
}
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -243,6 +252,7 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header
|
|||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTIPLProperties() const {
|
||||
|
||||
PropertyMap map;
|
||||
if (fieldList().size() % 2 != 0) {
|
||||
// according to the ID3 spec, TIPL must contain an even number of entries
|
||||
|
@ -266,9 +276,11 @@ PropertyMap TextIdentificationFrame::makeTIPLProperties() const {
|
|||
}
|
||||
}
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTMCLProperties() const {
|
||||
|
||||
PropertyMap map;
|
||||
if (fieldList().size() % 2 != 0) {
|
||||
// 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(","));
|
||||
}
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : TextIdentificationFrame("TXXX", encoding),
|
||||
d(0) {
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : TextIdentificationFrame("TXXX", encoding), d(nullptr) {
|
||||
StringList l;
|
||||
l.append(String());
|
||||
l.append(String());
|
||||
|
@ -306,13 +318,13 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data)
|
|||
checkFields();
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : TextIdentificationFrame("TXXX", encoding),
|
||||
d(0) {
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : TextIdentificationFrame("TXXX", encoding), d(nullptr) {
|
||||
setDescription(description);
|
||||
setText(values);
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::toString() const {
|
||||
|
||||
// first entry is the description itself, drop from values list
|
||||
StringList l = fieldList();
|
||||
for (StringList::Iterator it = l.begin(); it != l.end(); ++it) {
|
||||
|
@ -320,6 +332,7 @@ String UserTextIdentificationFrame::toString() const {
|
|||
break;
|
||||
}
|
||||
return "[" + description() + "] " + l.toString();
|
||||
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::description() const {
|
||||
|
@ -347,6 +360,7 @@ void UserTextIdentificationFrame::setText(const StringList &fields) {
|
|||
}
|
||||
|
||||
void UserTextIdentificationFrame::setDescription(const String &s) {
|
||||
|
||||
StringList l = fieldList();
|
||||
|
||||
if (l.isEmpty())
|
||||
|
@ -355,21 +369,22 @@ void UserTextIdentificationFrame::setDescription(const String &s) {
|
|||
l[0] = s;
|
||||
|
||||
TextIdentificationFrame::setText(l);
|
||||
|
||||
}
|
||||
|
||||
PropertyMap UserTextIdentificationFrame::asProperties() const {
|
||||
|
||||
PropertyMap map;
|
||||
String tagName = txxxToKey(description());
|
||||
StringList v = fieldList();
|
||||
for (StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
|
||||
if (it != v.begin())
|
||||
map.insert(tagName, *it);
|
||||
if (it != v.begin()) map.insert(tagName, *it);
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
||||
ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(ID3v2::Tag *tag, const String &description) { // static
|
||||
|
||||
FrameList l = tag->frameList("TXXX");
|
||||
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
|
||||
|
@ -377,6 +392,7 @@ UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
|||
return f;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -388,10 +404,12 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data,
|
|||
}
|
||||
|
||||
void UserTextIdentificationFrame::checkFields() {
|
||||
|
||||
int fields = fieldList().size();
|
||||
|
||||
if (fields == 0)
|
||||
setDescription(String());
|
||||
if (fields <= 1)
|
||||
setText(String());
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
namespace Strawberry_TagLib {
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Tag;
|
||||
|
@ -43,117 +42,111 @@ typedef Map<String, String> KeyConversionMap;
|
|||
//! An ID3v2 text identification frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of the most common type of ID3v2 frame -- text
|
||||
* identification frames. There are a number of variations on this. Those
|
||||
* enumerated in the ID3v2.4 standard are:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>TALB</b> Album/Movie/Show title</li>
|
||||
* <li><b>TBPM</b> BPM (beats per minute)</li>
|
||||
* <li><b>TCOM</b> Composer</li>
|
||||
* <li><b>TCON</b> Content type</li>
|
||||
* <li><b>TCOP</b> Copyright message</li>
|
||||
* <li><b>TDEN</b> Encoding time</li>
|
||||
* <li><b>TDLY</b> Playlist delay</li>
|
||||
* <li><b>TDOR</b> Original release time</li>
|
||||
* <li><b>TDRC</b> Recording time</li>
|
||||
* <li><b>TDRL</b> Release time</li>
|
||||
* <li><b>TDTG</b> Tagging time</li>
|
||||
* <li><b>TENC</b> Encoded by</li>
|
||||
* <li><b>TEXT</b> Lyricist/Text writer</li>
|
||||
* <li><b>TFLT</b> File type</li>
|
||||
* <li><b>TIPL</b> Involved people list</li>
|
||||
* <li><b>TIT1</b> Content group description</li>
|
||||
* <li><b>TIT2</b> Title/songname/content description</li>
|
||||
* <li><b>TIT3</b> Subtitle/Description refinement</li>
|
||||
* <li><b>TKEY</b> Initial key</li>
|
||||
* <li><b>TLAN</b> Language(s)</li>
|
||||
* <li><b>TLEN</b> Length</li>
|
||||
* <li><b>TMCL</b> Musician credits list</li>
|
||||
* <li><b>TMED</b> Media type</li>
|
||||
* <li><b>TMOO</b> Mood</li>
|
||||
* <li><b>TOAL</b> Original album/movie/show title</li>
|
||||
* <li><b>TOFN</b> Original filename</li>
|
||||
* <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li>
|
||||
* <li><b>TOPE</b> Original artist(s)/performer(s)</li>
|
||||
* <li><b>TOWN</b> File owner/licensee</li>
|
||||
* <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li>
|
||||
* <li><b>TPE2</b> Band/orchestra/accompaniment</li>
|
||||
* <li><b>TPE3</b> Conductor/performer refinement</li>
|
||||
* <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li>
|
||||
* <li><b>TPOS</b> Part of a set</li>
|
||||
* <li><b>TPRO</b> Produced notice</li>
|
||||
* <li><b>TPUB</b> Publisher</li>
|
||||
* <li><b>TRCK</b> Track number/Position in set</li>
|
||||
* <li><b>TRSN</b> Internet radio station name</li>
|
||||
* <li><b>TRSO</b> Internet radio station owner</li>
|
||||
* <li><b>TSOA</b> Album sort order</li>
|
||||
* <li><b>TSOP</b> Performer sort order</li>
|
||||
* <li><b>TSOT</b> Title sort order</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>TSST</b> Set subtitle</li>
|
||||
* </ul>
|
||||
*
|
||||
* The ID3v2 Frames document gives a description of each of these formats
|
||||
* and the expected order of strings in each. ID3v2::Header::frameID() can
|
||||
* be used to determine the frame type.
|
||||
*
|
||||
* \note If non-Latin1 compatible strings are used with this class, even if
|
||||
* the text encoding is set to Latin1, the frame will be written using UTF8
|
||||
* (with the encoding flag appropriately set in the output).
|
||||
*/
|
||||
* This is an implementation of the most common type of ID3v2 frame -- text identification frames.
|
||||
* There are a number of variations on this. Those enumerated in the ID3v2.4 standard are:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>TALB</b> Album/Movie/Show title</li>
|
||||
* <li><b>TBPM</b> BPM (beats per minute)</li>
|
||||
* <li><b>TCOM</b> Composer</li>
|
||||
* <li><b>TCON</b> Content type</li>
|
||||
* <li><b>TCOP</b> Copyright message</li>
|
||||
* <li><b>TDEN</b> Encoding time</li>
|
||||
* <li><b>TDLY</b> Playlist delay</li>
|
||||
* <li><b>TDOR</b> Original release time</li>
|
||||
* <li><b>TDRC</b> Recording time</li>
|
||||
* <li><b>TDRL</b> Release time</li>
|
||||
* <li><b>TDTG</b> Tagging time</li>
|
||||
* <li><b>TENC</b> Encoded by</li>
|
||||
* <li><b>TEXT</b> Lyricist/Text writer</li>
|
||||
* <li><b>TFLT</b> File type</li>
|
||||
* <li><b>TIPL</b> Involved people list</li>
|
||||
* <li><b>TIT1</b> Content group description</li>
|
||||
* <li><b>TIT2</b> Title/songname/content description</li>
|
||||
* <li><b>TIT3</b> Subtitle/Description refinement</li>
|
||||
* <li><b>TKEY</b> Initial key</li>
|
||||
* <li><b>TLAN</b> Language(s)</li>
|
||||
* <li><b>TLEN</b> Length</li>
|
||||
* <li><b>TMCL</b> Musician credits list</li>
|
||||
* <li><b>TMED</b> Media type</li>
|
||||
* <li><b>TMOO</b> Mood</li>
|
||||
* <li><b>TOAL</b> Original album/movie/show title</li>
|
||||
* <li><b>TOFN</b> Original filename</li>
|
||||
* <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li>
|
||||
* <li><b>TOPE</b> Original artist(s)/performer(s)</li>
|
||||
* <li><b>TOWN</b> File owner/licensee</li>
|
||||
* <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li>
|
||||
* <li><b>TPE2</b> Band/orchestra/accompaniment</li>
|
||||
* <li><b>TPE3</b> Conductor/performer refinement</li>
|
||||
* <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li>
|
||||
* <li><b>TPOS</b> Part of a set</li>
|
||||
* <li><b>TPRO</b> Produced notice</li>
|
||||
* <li><b>TPUB</b> Publisher</li>
|
||||
* <li><b>TRCK</b> Track number/Position in set</li>
|
||||
* <li><b>TRSN</b> Internet radio station name</li>
|
||||
* <li><b>TRSO</b> Internet radio station owner</li>
|
||||
* <li><b>TSOA</b> Album sort order</li>
|
||||
* <li><b>TSOP</b> Performer sort order</li>
|
||||
* <li><b>TSOT</b> Title sort order</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>TSST</b> Set subtitle</li>
|
||||
* </ul>
|
||||
*
|
||||
* The ID3v2 Frames document gives a description of each of these formats
|
||||
* and the expected order of strings in each.
|
||||
* ID3v2::Header::frameID() can be used to determine the frame type.
|
||||
*
|
||||
* \note If non-Latin1 compatible strings are used with this class,
|
||||
* even if the text encoding is set to Latin1, the frame will be written using UTF8
|
||||
* (with the encoding flag appropriately set in the output).
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty frame of type \a type. Uses \a encoding as the
|
||||
* default text encoding.
|
||||
*
|
||||
* \note In this case you must specify the text encoding as it
|
||||
* resolves the ambiguity between constructors.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*/
|
||||
* Construct an empty frame of type \a type.
|
||||
* Uses \a encoding as the default text encoding.
|
||||
*
|
||||
* \note In this case you must specify the text encoding as it resolves the ambiguity between constructors.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*/
|
||||
TextIdentificationFrame(const ByteVector &type, String::Type encoding);
|
||||
|
||||
/*!
|
||||
* This is a dual purpose constructor. \a data can either be binary data
|
||||
* that should be parsed or (at a minimum) the frame ID.
|
||||
*/
|
||||
* This is a dual purpose constructor.
|
||||
* \a data can either be binary data that should be parsed or (at a minimum) the frame ID.
|
||||
*/
|
||||
explicit TextIdentificationFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* This is a special factory method to create a TIPL (involved people list)
|
||||
* frame from the given \a properties. Will parse key=[list of values] data
|
||||
* into the TIPL format as specified in the ID3 standard.
|
||||
*/
|
||||
* This is a special factory method to create a TIPL (involved people list) frame from the given \a properties.
|
||||
* Will parse key=[list of values] data into the TIPL format as specified in the ID3 standard.
|
||||
*/
|
||||
static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);
|
||||
|
||||
/*!
|
||||
* This is a special factory method to create a TMCL (musician credits list)
|
||||
* frame from the given \a properties. 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.
|
||||
*/
|
||||
* This is a special factory method to create a TMCL (musician credits list) frame from the given \a properties.
|
||||
* 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.
|
||||
*/
|
||||
static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
|
||||
/*!
|
||||
* Destroys this TextIdentificationFrame instance.
|
||||
*/
|
||||
* Destroys this TextIdentificationFrame instance.
|
||||
*/
|
||||
virtual ~TextIdentificationFrame();
|
||||
|
||||
/*!
|
||||
* Text identification frames are a list of string fields.
|
||||
*
|
||||
* This function will accept either a StringList or a String (using the
|
||||
* StringList constructor that accepts a single String).
|
||||
*
|
||||
* \note This will not change the text encoding of the frame even if the
|
||||
* strings passed in are not of the same encoding. Please use
|
||||
* setEncoding(s.type()) if you wish to change the encoding of the frame.
|
||||
*/
|
||||
* Text identification frames are a list of string fields.
|
||||
*
|
||||
* This function will accept either a StringList or a String (using the
|
||||
* StringList constructor that accepts a single String).
|
||||
*
|
||||
* \note This will not change the text encoding of the frame even if the strings passed in are not of the same encoding.
|
||||
* Please use setEncoding(s.type()) if you wish to change the encoding of the frame.
|
||||
*/
|
||||
void setText(const StringList &l);
|
||||
|
||||
// Reimplementations.
|
||||
|
@ -162,37 +155,34 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
|
|||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
* Sets the text encoding to be used when rendering this frame to \a encoding.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
static const KeyConversionMap &involvedPeopleMap();
|
||||
|
||||
PropertyMap asProperties() const;
|
||||
|
@ -204,8 +194,8 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
|
|||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
TextIdentificationFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
|
@ -213,26 +203,25 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
|
|||
TextIdentificationFrame &operator=(const TextIdentificationFrame &);
|
||||
|
||||
/*!
|
||||
* Parses the special structure of a TIPL frame
|
||||
* Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
|
||||
* "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
|
||||
*/
|
||||
* Parses the special structure of a TIPL frame
|
||||
* Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
|
||||
* "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
|
||||
*/
|
||||
PropertyMap makeTIPLProperties() const;
|
||||
/*!
|
||||
* Parses the special structure of a TMCL frame.
|
||||
*/
|
||||
* Parses the special structure of a TMCL frame.
|
||||
*/
|
||||
PropertyMap makeTMCLProperties() const;
|
||||
class TextIdentificationFramePrivate;
|
||||
TextIdentificationFramePrivate *d;
|
||||
};
|
||||
|
||||
/*!
|
||||
* This is a specialization of text identification frames that allows for
|
||||
* user defined entries. Each entry has a description in addition to the
|
||||
* normal list of fields that a text identification frame has.
|
||||
*
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
* This is a specialization of text identification frames that allows for user defined entries.
|
||||
* Each entry has a description in addition to the normal list of fields that a text identification frame has.
|
||||
*
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
|
||||
//! An ID3v2 custom text identification frame implementation
|
||||
|
||||
|
@ -241,34 +230,32 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
|
|||
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty user defined text identification frame. For this to be
|
||||
* a useful frame both a description and text must be set.
|
||||
*/
|
||||
* Constructs an empty user defined text identification frame.
|
||||
* For this to be a useful frame both a description and text must be set.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Creates a user defined text identification frame with the given \a description
|
||||
* and \a values.
|
||||
*/
|
||||
* Creates a user defined text identification frame with the given \a description and \a values.
|
||||
*/
|
||||
UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8);
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the description for this frame.
|
||||
*/
|
||||
* Returns the description for this frame.
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the description of the frame to \a s. \a s must be unique. You can
|
||||
* check for the presence of another user defined text frame of the same type
|
||||
* using find() and testing for null.
|
||||
*/
|
||||
* Sets the description of the frame to \a s. \a s must be unique.
|
||||
* You can check for the presence of another user defined text frame of the same type using find() and testing for null.
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
StringList fieldList() const;
|
||||
|
@ -276,24 +263,19 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
|
|||
void setText(const StringList &fields);
|
||||
|
||||
/*!
|
||||
* A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
|
||||
* - the key is the frame's description, uppercased
|
||||
* - if the description contains '::', only the substring after that
|
||||
* 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.
|
||||
* - 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().
|
||||
*/
|
||||
* A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
|
||||
* - the key is the frame's description, uppercased
|
||||
* - if the description contains '::', only the substring after that 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.
|
||||
* - 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;
|
||||
|
||||
/*!
|
||||
* Searches for the user defined text frame with the description \a description
|
||||
* in \a tag. This returns null if no matching frames were found.
|
||||
*/
|
||||
* Searches for the user defined text frame with the description \a description in \a tag.
|
||||
* This returns null if no matching frames were found.
|
||||
*/
|
||||
static UserTextIdentificationFrame *find(Tag *tag, const String &description);
|
||||
|
||||
private:
|
||||
|
@ -310,4 +292,5 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
|
|||
} // namespace ID3v2
|
||||
} // namespace TagLib
|
||||
} // namespace Strawberry_TagLib
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue