Additional manual formatting to taglib sources

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

View File

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

View File

@ -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);
}
}

View File

@ -55,8 +55,8 @@ class Tag;
/*!
* 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 supports ID3v1 and APE (v1 and v2) style comments as well as reading stream properties from the file.
*
*/
namespace APE {
@ -66,15 +66,14 @@ namespace APE {
/*!
* 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.
* 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.
@ -88,8 +87,8 @@ 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.
* 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.
*/
@ -97,11 +96,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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.
* 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 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.
*/
@ -114,34 +112,31 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::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.
* 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.
* 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;
@ -156,17 +151,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* Returns a pointer to the ID3v1 tag of the file.
*
* If \a create is false (the default) this may return a null pointer
* if 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.
* 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 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.
* \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()
*/
@ -175,28 +167,24 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* Returns a pointer to the APE tag of the file.
*
* If \a create is false (the default) this may return a null pointer
* if 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 \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 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.
* \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.
* 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 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);
@ -216,11 +204,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
bool hasID3v1Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as an APE
* file.
* 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.
* \note This method is designed to do a quick check.
* The result may not necessarily be correct.
*/
static bool isSupported(IOStream *stream);

View File

@ -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;
}

View File

@ -37,10 +37,11 @@ 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 {
@ -51,8 +52,7 @@ class TAGLIB_EXPORT 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);
@ -98,7 +98,8 @@ class TAGLIB_EXPORT Footer {
void setItemCount(unsigned int s);
/*!
* Returns the tag size in bytes. This is the size of the frame content and footer.
* Returns the tag size in bytes.
* 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()
@ -142,15 +143,15 @@ class TAGLIB_EXPORT Footer {
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);

View File

@ -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;
}

View File

@ -32,7 +32,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace APE {
//! An implementation of APE-items
@ -130,8 +129,7 @@ class TAGLIB_EXPORT Item {
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.
* Sets the text value of the item to the list of values in \a value and clears any previous contents.
*
* \see toStringList()
*/
@ -157,20 +155,14 @@ class TAGLIB_EXPORT 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;
@ -216,7 +208,6 @@ class TAGLIB_EXPORT Item {
ItemPrivate *d;
};
} // namespace APE
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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);
}

View File

@ -35,7 +35,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace APE {
class File;
@ -43,23 +42,14 @@ 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);
@ -69,18 +59,7 @@ 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.
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
*
* \see lengthInMilliseconds()
*/

View File

@ -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;
}
}

View File

@ -74,14 +74,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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();
@ -106,24 +104,23 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* 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*
* 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).
* 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.
* 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
* 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+".
*/
@ -140,8 +137,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
Footer *footer() const;
/*!
* Returns a reference to the item list map. This is an ItemListMap of
* all of the items in the tag.
* 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.
*
@ -159,22 +156,20 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::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.
* 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);

View File

@ -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 {

View File

@ -33,7 +33,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ASF {
class File;
@ -199,7 +198,6 @@ class TAGLIB_EXPORT Attribute {
AttributePrivate *d;
};
} // namespace ASF
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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;
}
}

View File

@ -66,8 +66,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
* \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);
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
@ -92,8 +91,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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);
@ -115,11 +113,9 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as an ASF
* file.
* 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.
* \note This method is designed to do a quick check. The result may not necessarily be correct.
*/
static bool isSupported(IOStream *stream);

View File

@ -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) {
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;
}

View File

@ -38,10 +38,9 @@ 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.
* 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)
*/
@ -126,8 +125,7 @@ class TAGLIB_EXPORT Picture {
bool isValid() const;
/*!
* 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".
* \see setMimeType(const String &)
* \see picture()
* \see setPicture(const ByteArray&)
@ -135,8 +133,7 @@ class TAGLIB_EXPORT Picture {
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".
* \see setMimeType(const String &)
* \see picture()
* \see setPicture(const ByteArray&)
@ -176,8 +173,7 @@ class TAGLIB_EXPORT Picture {
/*!
* 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.
* \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()
@ -185,8 +181,8 @@ class TAGLIB_EXPORT Picture {
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.
* 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()

View File

@ -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) {

View File

@ -32,7 +32,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ASF {
//! An implementation of ASF audio properties
@ -78,16 +77,6 @@ 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
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
@ -134,8 +123,7 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
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.
* 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()
@ -144,8 +132,7 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
/*!
* 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.
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available, otherwise an empty string.
*
* \see codec()
* \see codecName()

View File

@ -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;
}

View File

@ -60,8 +60,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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;
@ -71,8 +70,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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;
@ -82,8 +80,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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;
@ -93,8 +90,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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;
@ -109,8 +105,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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);
@ -145,23 +140,15 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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
* Returns a reference to the item list map. This is an AttributeListMap of all of the items in the tag.
*/
AttributeListMap &attributeListMap();
/*!
* 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;
const AttributeListMap attributeListMap() const;
/*!
* \return True if a value for \a attribute is currently set.
@ -174,14 +161,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::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);

View File

@ -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) {}

View File

@ -34,9 +34,9 @@ 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.
*/
@ -44,10 +44,9 @@ 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.
* 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
@ -66,11 +65,10 @@ class TAGLIB_EXPORT AudioProperties {
/*!
* Returns the length of the file in seconds.
*/
virtual int length() const = 0;
//virtual int length() const = 0;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
*
* \see lengthInMilliseconds()
*/
@ -86,9 +84,8 @@ class TAGLIB_EXPORT AudioProperties {
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;
@ -104,9 +101,9 @@ class TAGLIB_EXPORT AudioProperties {
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.
* 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
*/

View File

@ -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;
}

View File

@ -30,9 +30,7 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace DSDIFF {
namespace DIIN {
/*!
@ -40,20 +38,19 @@ namespace DIIN {
*
* 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;
@ -83,14 +80,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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);
@ -128,10 +123,9 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* 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.
* 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 &);

View File

@ -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);
}

View File

@ -41,10 +41,9 @@ namespace TagLib {
*
* 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
* 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
* 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
*/
@ -54,9 +53,8 @@ namespace DSDIFF {
/*!
* 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.
* 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 {
@ -77,20 +75,18 @@ 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.
* 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);
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.
* 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 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.
*/
@ -103,17 +99,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::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,
* 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.
* 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.
* but a union of the two this pointer may not be cast to the specific tag types.
*
* \see ID3v2Tag()
* \see DIINTag()
@ -123,9 +116,8 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* \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()
*/
@ -152,18 +144,16 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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.
* 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.
* 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);
*
@ -175,17 +165,15 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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.
* 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.
*/
@ -199,25 +187,24 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
bool hasID3v2Tag() const;
/*!
* Returns whether or not the file on disk actually has the DSDIFF
* title and artist tags.
* 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.
* 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.
* \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);
@ -239,9 +226,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* 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.
*/
@ -254,13 +239,11 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
*
* \warning This will update the file immediately.
*/
void setChildChunkData(unsigned int i, const ByteVector &data,
unsigned int childChunkNum);
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.
* 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
*
@ -272,9 +255,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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;

View File

@ -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() {

View File

@ -30,7 +30,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace DSDIFF {
class File;
@ -38,19 +37,15 @@ 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.
* 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);
Properties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle style);
/*!
* Destroys this DSDIFF::Properties instance.
@ -76,6 +71,7 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
class PropertiesPrivate;
PropertiesPrivate *d;
};
} // namespace DSDIFF
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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);
}

View File

@ -48,24 +48,24 @@ namespace DSF {
/*!
* 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.
* 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);
@ -93,8 +93,8 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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;
@ -104,11 +104,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as a DSF
* file.
* 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.
* \note This method is designed to do a quick check.
* The result may not necessarily be correct.
*/
static bool isSupported(IOStream *stream);

View File

@ -30,7 +30,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace DSF {
class File;
@ -38,15 +37,13 @@ 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);
@ -68,8 +65,14 @@ 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;

View File

@ -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);
}

View File

@ -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,27 +79,23 @@ 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.
* 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.
* \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;
};
/*!
@ -112,10 +104,9 @@ class TAGLIB_EXPORT 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.
* 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.
@ -126,16 +117,13 @@ class TAGLIB_EXPORT FileRef {
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.
* 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.
* Also see the note in the class documentation about why you may not want to use this method in your application.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
* \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object.
*/
explicit FileRef(IOStream *stream,
bool readAudioProperties = true,
@ -143,8 +131,8 @@ class TAGLIB_EXPORT FileRef {
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);
@ -172,8 +160,8 @@ class TAGLIB_EXPORT FileRef {
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;
@ -200,14 +188,12 @@ class TAGLIB_EXPORT FileRef {
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.
* 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).
* this is mostly so that static initializers have something to use for assignment).
*
* \see FileTypeResolver
*/
@ -215,8 +201,7 @@ class TAGLIB_EXPORT FileRef {
/*!
* As is mentioned elsewhere in this class's documentation, the default file
* type resolution code provided by TagLib only works by comparing file
* extensions.
* 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.
*
@ -252,19 +237,16 @@ class TAGLIB_EXPORT FileRef {
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.
* 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.
* \note You generally shouldn't use this method, but instead the constructor directly.
*
* \deprecated
*/

View File

@ -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;
}

View File

@ -65,10 +65,9 @@ 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 {
@ -91,47 +90,26 @@ 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.
* 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.
*
* \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);
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.
* Constructs a FLAC file from \a stream. 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 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);
/*!
* 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);
File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
@ -139,8 +117,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
virtual ~File();
/*!
* Returns the Tag for this file. This will be a union of XiphComment,
* ID3v1 and ID3v2 tags.
* Returns the Tag for this file. This will be a union of XiphComment, ID3v1 and ID3v2 tags.
*
* \see ID3v2Tag()
* \see ID3v1Tag()
@ -150,9 +127,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* 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;
@ -160,23 +135,19 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* 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.
* 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.
*/
@ -186,16 +157,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
* 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.
* 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 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.
* deleted by the user. It will be deleted when the file (object) is destroyed.
*
* \see hasID3v2Tag()
*/
@ -204,17 +173,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* 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 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.
* \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()
*/
@ -223,56 +189,27 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* 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 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.
* \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.
*/
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);
@ -282,25 +219,23 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
void removePictures();
/*!
* Add a new picture to the file. The file takes ownership of the
* picture and will handle freeing its memory.
* 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.
* 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.
* \warning This will also invalidate pointers to the tags as their memory will be freed.
*
* \note In order to make the removal permanent save() still needs to be
* called.
* \note In order to make the removal permanent save() still needs to be called.
*
* \note This won't remove the Vorbis comment block completely. The
* vendor ID will be preserved.
* \note This won't remove the Vorbis comment block completely.
* The vendor ID will be preserved.
*/
void strip(int tags = AllTags);
@ -326,11 +261,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
bool hasID3v2Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as a FLAC
* file.
* 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.
* \note This method is designed to do a quick check.
* The result may not necessarily be correct.
*/
static bool isSupported(IOStream *stream);

View File

@ -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() {}

View File

@ -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

View File

@ -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 {

View File

@ -102,14 +102,12 @@ class TAGLIB_EXPORT Picture : public MetadataBlock {
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);
@ -201,7 +199,6 @@ class TAGLIB_EXPORT Picture : public MetadataBlock {
typedef List<Picture> PictureList;
} // namespace FLAC
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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);
}

View File

@ -39,25 +39,15 @@ 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.
* 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
* FLAC::File \a file.
*/
// BIC: remove
Properties(File *file, ReadStyle style = Average);
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
/*!
* Destroys this FLAC::Properties instance.
@ -65,18 +55,7 @@ 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.
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
*
* \see lengthInMilliseconds()
*/
@ -107,29 +86,17 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
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.
*/
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;

View File

@ -33,7 +33,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace FLAC {
class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
@ -75,7 +74,6 @@ class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock {
};
} // namespace FLAC
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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");
}

View File

@ -31,7 +31,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace IT {
class TAGLIB_EXPORT File : public Mod::FileBase {
@ -39,9 +38,8 @@ class TAGLIB_EXPORT File : public Mod::FileBase {
/*!
* 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.
* \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 =
@ -50,12 +48,10 @@ class TAGLIB_EXPORT File : public Mod::FileBase {
/*!
* 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 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.
* \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 =
@ -104,6 +100,7 @@ class TAGLIB_EXPORT File : public Mod::FileBase {
class FilePrivate;
FilePrivate *d;
};
} // namespace IT
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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;

View File

@ -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"));
}

View File

@ -35,7 +35,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
@ -43,27 +42,21 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
/*!
* 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.
* \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);
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 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);
File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Destroys this instance of the File.
@ -84,8 +77,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
*/
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;
@ -108,7 +100,6 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase {
};
} // namespace Mod
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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;
}

View File

@ -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

View File

@ -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() {

View File

@ -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

View File

@ -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;
}

View File

@ -30,20 +30,19 @@
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.
* 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.
* 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:
@ -51,8 +50,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::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;
@ -68,8 +66,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* Returns the track comment derived from the instrument/sample/pattern
* names; if no comment is present in the tag String::null will be
* returned.
* names; if no comment is present in the tag String::null will be returned.
*/
virtual String comment() const;
@ -91,19 +88,17 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* 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.
* (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.
* 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.
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 characters.
*/
virtual void setTitle(const String &title);
@ -118,21 +113,18 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
virtual void setAlbum(const String &album);
/*!
* Sets the comment to \a comment. If \a comment is String::null then
* this value will be cleared.
* 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.
* 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.
* 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.
* Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22 characters.
*/
virtual void setComment(const String &comment);
@ -152,14 +144,13 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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.
* 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.
* 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).
* The length of this tag is limited to 20 characters (1 character = 1 byte).
*/
void setTrackerName(const String &trackerName);
@ -171,11 +162,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* 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.
* 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 &);
@ -188,7 +176,6 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
};
} // namespace Mod
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -33,7 +33,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace MP4 {
class TAGLIB_EXPORT CoverArt {
@ -78,7 +77,6 @@ class TAGLIB_EXPORT CoverArt {
typedef List<CoverArt> CoverArtList;
} // namespace MP4
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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);
}

View File

@ -49,17 +49,16 @@ class Atoms;
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.
* 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);
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.
* 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.
@ -77,12 +76,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::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().
* 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.
* \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;
@ -92,8 +89,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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);
@ -115,17 +111,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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.
* 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.
* \note This method is designed to do a quick check. The result may not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
@ -137,7 +130,6 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
};
} // namespace MP4
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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;
}

View File

@ -32,7 +32,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace MP4 {
class TAGLIB_EXPORT Item {
@ -87,7 +86,6 @@ class TAGLIB_EXPORT Item {
};
} // namespace MP4
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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;
}
}

View File

@ -31,7 +31,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace MP4 {
class Atoms;
@ -50,18 +49,7 @@ 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.
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
*
* \see lengthInMilliseconds()
*/
@ -114,7 +102,6 @@ class TAGLIB_EXPORT Properties : public AudioProperties {
};
} // namespace MP4
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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 + "\"");
}
}

View File

@ -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,12 +65,6 @@ 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.
*/
@ -92,8 +81,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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);
@ -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

View File

@ -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);
}
}

View File

@ -51,9 +51,9 @@ class Tag;
/*!
* 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 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 {
@ -61,18 +61,14 @@ 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.
* 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.
@ -88,25 +84,22 @@ 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.
* 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);
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.
* 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 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);
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
@ -114,15 +107,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::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.
* If the file contains both an APE and an ID3v1 tag, only the APE tag will be converted to the PropertyMap.
*/
PropertyMap properties() const;
@ -136,8 +128,8 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
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;
@ -151,17 +143,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* 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.
* 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 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.
* \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()
*/
@ -171,39 +160,29 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
* Returns a pointer to the APE tag of the file.
*
* If \a create is false (the default) this may return a null pointer
* if 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.
* 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 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.
* \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.
* 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.
* \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.
*
@ -219,11 +198,9 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
bool hasAPETag() const;
/*!
* Returns whether or not the given \a stream can be opened as an MPC
* file.
* 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.
* \note This method is designed to do a quick check. The result may not necessarily be correct.
*/
static bool isSupported(IOStream *stream);

View File

@ -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);
}
}

View File

@ -41,23 +41,20 @@ 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.
* 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);
@ -67,18 +64,8 @@ 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.
* Returns the length of the file in seconds.
* The length is rounded down to the nearest whole second.
*
* \see lengthInMilliseconds()
*/

View File

@ -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;
}

View File

@ -37,28 +37,24 @@ 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

View File

@ -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]);
}

View File

@ -42,42 +42,38 @@ 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.
* 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.
* 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.
* \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.
* 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.
* 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;
};
@ -85,21 +81,20 @@ class TAGLIB_EXPORT StringHandler {
//! 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.
* 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.
* 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.
* \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 {
@ -110,8 +105,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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);
@ -121,14 +115,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
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();
@ -160,19 +152,15 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* 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.
* \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.
* 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.
* \note The caller is responsible for deleting the previous handler as needed after it is released.
*
* \see StringHandler
*/
@ -195,6 +183,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
class TagPrivate;
TagPrivate *d;
};
} // namespace ID3v1
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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);
}

View File

@ -32,16 +32,14 @@
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 {
@ -97,8 +95,8 @@ 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();
@ -133,14 +131,14 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
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);
@ -183,8 +181,7 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
/*!
* 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.
* \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()
@ -192,8 +189,7 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
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.
* 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()
@ -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

View File

@ -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));
}

View File

@ -32,12 +32,11 @@
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,17 +46,16 @@ 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,
* 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;
* whose ownership will then be taken over by this Frame, in \a embeededFrames;
*
* All times are in milliseconds.
*/
@ -72,8 +70,8 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
virtual ~ChapterFrame();
/*!
* Returns the element ID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
* Returns the element ID of the frame.
* Element ID is a null terminated string, however it's not human-readable.
*
* \see setElementID()
*/
@ -94,8 +92,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
unsigned int endTime() const;
/*!
* Returns zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's start.
* 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()
@ -103,8 +100,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
unsigned int startOffset() const;
/*!
* Returns zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's end.
* 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()
@ -112,8 +108,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
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.
* 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()
*/
@ -134,29 +129,26 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
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.
* 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.
* 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.
* 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.
* 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().
@ -166,22 +158,20 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
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.
* 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().
* \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:
* 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];
@ -192,29 +182,25 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
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.
* 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()
* \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.
* 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()
* \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.
* 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()
* \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id);
@ -223,9 +209,8 @@ 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.
* 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()
*/
@ -243,6 +228,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
class ChapterFramePrivate;
ChapterFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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));
}

View File

@ -31,7 +31,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
//! An implementation of ID3v2 comments
@ -46,8 +45,7 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
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);
@ -96,8 +94,7 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
/*!
* 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.
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to \a languageCode.
*
* \see language()
*/
@ -119,8 +116,7 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
*
* \see setTextEncoding()
* \see render()
@ -128,8 +124,7 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
String::Type textEncoding() const;
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
* Sets the text encoding to be used when rendering this frame to \a encoding.
*
* \see textEncoding()
* \see render()
@ -148,9 +143,9 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
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.
* 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()
*/
@ -177,4 +172,5 @@ class TAGLIB_EXPORT CommentsFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -31,7 +31,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
//! ID3v2 event timing codes frame
@ -182,4 +181,5 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -35,7 +35,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
//! An ID3v2 general encapsulated object frame implementation
@ -43,10 +42,10 @@ namespace ID3v2 {
/*!
* 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.
* 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 {
@ -54,8 +53,8 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
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();
@ -63,8 +62,8 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
* 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.
* setObject().
* This constructor is used when reading the frame from the disk.
*/
explicit GeneralEncapsulatedObjectFrame(const ByteVector &data);
@ -151,8 +150,8 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
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.
* 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()
@ -172,6 +171,7 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
class GeneralEncapsulatedObjectFramePrivate;
GeneralEncapsulatedObjectFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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));
}

View File

@ -31,14 +31,13 @@
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 {
@ -111,8 +110,7 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
*
* \see setTextEncoding()
* \see render()
@ -120,8 +118,7 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
String::Type textEncoding() const;
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
* Sets the text encoding to be used when rendering this frame to \a encoding.
*
* \see textEncoding()
* \see render()
@ -149,4 +146,5 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -31,7 +31,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
//! ID3v2 podcast frame
@ -78,4 +77,5 @@ class TAGLIB_EXPORT PodcastFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -31,14 +31,13 @@
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 {
@ -130,4 +129,5 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -32,7 +32,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
//! An implementation of ID3v2 privateframe
@ -109,4 +108,5 @@ class TAGLIB_EXPORT PrivateFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -32,19 +32,15 @@
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.
* 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.
* 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 {
@ -78,8 +74,8 @@ 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 {
/*!
@ -87,20 +83,17 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
*/
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();
@ -126,31 +119,17 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public 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.
* 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.
* 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()
@ -158,9 +137,8 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
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.
* 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.
*
@ -173,11 +151,9 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
* 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().
* 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.
* 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()
@ -189,9 +165,7 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
*
* 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().
* \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()
@ -201,8 +175,7 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
/*!
* 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.
* 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()
*/
@ -219,8 +192,7 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
#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;
@ -248,9 +220,8 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public 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);
@ -270,4 +241,5 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -31,7 +31,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
//! ID3v2 synchronized lyrics frame
@ -95,8 +94,7 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
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);
@ -119,8 +117,7 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
* This defaults to the type that was either specified in the constructor or read from the frame when parsed.
*
* \see setTextEncoding()
* \see render()
@ -162,8 +159,7 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
SynchedTextList synchedText() const;
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
* Sets the text encoding to be used when rendering this frame to \a encoding.
*
* \see textEncoding()
* \see render()
@ -172,8 +168,7 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
/*!
* 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.
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to \a languageCode.
*
* \see language()
*/
@ -228,4 +223,5 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@ -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));
}

View File

@ -33,12 +33,11 @@
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,15 +47,14 @@ 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.
* 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(),
@ -68,32 +66,29 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
~TableOfContentsFrame();
/*!
* Returns the elementID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
* 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).
* 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.
* 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.
* Returns count of child elements of the frame. It always corresponds to size of child elements list.
*
* \see childElements()
*/
@ -107,24 +102,21 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
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.
* 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).
* 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.
* Sets, if the child elements list entries are ordered.
*
* \see isOrdered()
*/
@ -152,38 +144,32 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
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.
* 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.
* 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().
* \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.
* 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.
* This can be useful if for example you want iterate over the CTOC frame's embedded frames in the order that they occur in the CTOC frame.
*
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
* \warning You should not modify this data structure directly, instead use addEmbeddedFrame() and removeEmbeddedFrame().
*/
const FrameList &embeddedFrameList() const;
/*!
* 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:
* 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];
@ -194,29 +180,25 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
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.
* 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()
* \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.
* 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()
* \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.
* 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()
* \note Using this method will invalidate any pointers on the list returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id);
@ -225,18 +207,18 @@ 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.
* 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.
* 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()
*/
@ -254,6 +236,7 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
class TableOfContentsFramePrivate;
TableOfContentsFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib

View File

@ -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());
}

View File

@ -34,7 +34,6 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
class Tag;
@ -43,9 +42,8 @@ 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:
* 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>
@ -96,11 +94,11 @@ typedef Map<String, String> KeyConversionMap;
* </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.
* 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
* \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).
*/
@ -109,34 +107,30 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
public:
/*!
* Construct an empty frame of type \a type. Uses \a encoding as the
* default text encoding.
* 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 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);
/*!
@ -150,9 +144,8 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
* 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.
* \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);
@ -163,8 +156,7 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
* 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.
*
@ -174,8 +166,7 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
String::Type textEncoding() const;
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
* 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.
*
@ -190,8 +181,7 @@ class TAGLIB_EXPORT TextIdentificationFrame : public 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();
@ -227,9 +217,8 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
};
/*!
* 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 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.
*/
@ -241,8 +230,8 @@ 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);
@ -252,8 +241,7 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
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);
@ -265,9 +253,8 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
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);
@ -278,21 +265,16 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
/*!
* 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.
* - 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().
* - 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);
@ -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