diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apefile.cpp clementine-1.3.1-218/3rdparty/taglib/ape/apefile.cpp --- clementine-1.3.1-217/3rdparty/taglib/ape/apefile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apefile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -38,9 +38,9 @@ #include #include #include +#include #include "apefile.h" - #include "apetag.h" #include "apefooter.h" @@ -61,10 +61,7 @@ ID3v2Header(0), ID3v2Location(-1), ID3v2Size(0), - properties(0), - hasAPE(false), - hasID3v1(false), - hasID3v2(false) {} + properties(0) {} ~FilePrivate() { @@ -73,24 +70,17 @@ } long APELocation; - uint APESize; + long APESize; long ID3v1Location; ID3v2::Header *ID3v2Header; long ID3v2Location; - uint ID3v2Size; + long ID3v2Size; TagUnion tag; Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasAPE; - bool hasID3v1; - bool hasID3v2; }; //////////////////////////////////////////////////////////////////////////////// @@ -125,26 +115,20 @@ PropertyMap APE::File::properties() const { - if(d->hasAPE) - return d->tag.access(ApeAPEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access(ApeID3v1Index, false)->properties(); - return PropertyMap(); + return d->tag.properties(); } void APE::File::removeUnsupportedProperties(const StringList &properties) { - if(d->hasAPE) - d->tag.access(ApeAPEIndex, false)->removeUnsupportedProperties(properties); - if(d->hasID3v1) - d->tag.access(ApeID3v1Index, false)->removeUnsupportedProperties(properties); + d->tag.removeUnsupportedProperties(properties); } PropertyMap APE::File::setProperties(const PropertyMap &properties) { - if(d->hasID3v1) - d->tag.access(ApeID3v1Index, false)->setProperties(properties); - return d->tag.access(ApeAPEIndex, true)->setProperties(properties); + if(ID3v1Tag()) + ID3v1Tag()->setProperties(properties); + + return APETag(true)->setProperties(properties); } APE::Properties *APE::File::audioProperties() const @@ -161,64 +145,67 @@ // Update ID3v1 tag - if(ID3v1Tag()) { - if(d->hasID3v1) { + if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { + + // ID3v1 tag is not empty. Update the old one or create a new one. + + if(d->ID3v1Location >= 0) { seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); } else { seek(0, End); d->ID3v1Location = tell(); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; } + + writeBlock(ID3v1Tag()->render()); } else { - if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->hasID3v1 = false; - if(d->hasAPE) { - if(d->APELocation > d->ID3v1Location) - d->APELocation -= 128; - } + + // ID3v1 tag is empty. Remove the old one. + + if(d->ID3v1Location >= 0) { + truncate(d->ID3v1Location); + d->ID3v1Location = -1; } } // Update APE tag - if(APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APESize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; + if(APETag() && !APETag()->isEmpty()) { + + // APE tag is not empty. Update the old one or create a new one. + + if(d->APELocation < 0) { + if(d->ID3v1Location >= 0) d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APESize; - } - else { - seek(0, End); - d->APELocation = tell(); - writeBlock(APETag()->render()); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } + else + d->APELocation = length(); } + + const ByteVector data = APETag()->render(); + insert(data, d->APELocation, d->APESize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->APESize); + + d->APESize = data.size(); } else { - if(d->hasAPE) { + + // APE tag is empty. Remove the old one. + + if(d->APELocation >= 0) { removeBlock(d->APELocation, d->APESize); - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) { - d->ID3v1Location -= d->APESize; - } - } + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->APESize; + + d->APELocation = -1; + d->APESize = 0; } } - return true; + return true; } ID3v1::Tag *APE::File::ID3v1Tag(bool create) @@ -233,27 +220,24 @@ void APE::File::strip(int tags) { - if(tags & ID3v1) { + if(tags & ID3v1) d->tag.set(ApeID3v1Index, 0); - APETag(true); - } - if(tags & APE) { + if(tags & APE) d->tag.set(ApeAPEIndex, 0); - if(!ID3v1Tag()) - APETag(true); - } + if(!ID3v1Tag()) + APETag(true); } bool APE::File::hasAPETag() const { - return d->hasAPE; + return (d->APELocation >= 0); } bool APE::File::hasID3v1Tag() const { - return d->hasID3v1; + return (d->ID3v1Location >= 0); } //////////////////////////////////////////////////////////////////////////////// @@ -264,36 +248,32 @@ { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { seek(d->ID3v2Location); d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); d->ID3v2Size = d->ID3v2Header->completeTagSize(); - d->hasID3v2 = true; } // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); - if(d->ID3v1Location >= 0) { + if(d->ID3v1Location >= 0) d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } // Look for an APE tag - d->APELocation = findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation)); d->APESize = APETag()->footer()->completeTagSize(); - d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; - d->hasAPE = true; + d->APELocation = d->APELocation + APE::Footer::size() - d->APESize; } - if(!d->hasID3v1) + if(d->ID3v1Location < 0) APETag(true); // Look for APE audio properties @@ -302,14 +282,14 @@ long streamLength; - if(d->hasAPE) + if(d->APELocation >= 0) streamLength = d->APELocation; - else if(d->hasID3v1) + else if(d->ID3v1Location >= 0) streamLength = d->ID3v1Location; else streamLength = length(); - if(d->hasID3v2) { + if(d->ID3v2Location >= 0) { seek(d->ID3v2Location + d->ID3v2Size); streamLength -= (d->ID3v2Location + d->ID3v2Size); } @@ -320,48 +300,3 @@ d->properties = new Properties(this, streamLength); } } - -long APE::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -long APE::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long APE::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apefile.h clementine-1.3.1-218/3rdparty/taglib/ape/apefile.h --- clementine-1.3.1-217/3rdparty/taglib/ape/apefile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apefile.h 2016-07-19 15:25:23.000000000 +0000 @@ -146,9 +146,6 @@ * * \note According to the official Monkey's Audio SDK, an APE file * can only have either ID3V1 or APE tags, so a parameter is used here. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ virtual bool save(); @@ -219,9 +216,6 @@ File &operator=(const File &); void read(bool readProperties); - long findAPE(); - long findID3v1(); - long findID3v2(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apefooter.cpp clementine-1.3.1-218/3rdparty/taglib/ape/apefooter.cpp --- clementine-1.3.1-217/3rdparty/taglib/ape/apefooter.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apefooter.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -38,54 +38,51 @@ class APE::Footer::FooterPrivate { public: - FooterPrivate() : version(0), - footerPresent(true), - headerPresent(false), - isHeader(false), - itemCount(0), - tagSize(0) {} + FooterPrivate() : + version(0), + footerPresent(true), + headerPresent(false), + isHeader(false), + itemCount(0), + tagSize(0) {} - ~FooterPrivate() {} - - uint version; + unsigned int version; bool footerPresent; bool headerPresent; bool isHeader; - uint itemCount; - uint tagSize; - - static const uint size = 32; + unsigned int itemCount; + unsigned int tagSize; }; //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// -TagLib::uint APE::Footer::size() +unsigned int APE::Footer::size() { - return FooterPrivate::size; + return 32; } ByteVector APE::Footer::fileIdentifier() { - return ByteVector::fromCString("APETAGEX"); + return ByteVector("APETAGEX"); } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -APE::Footer::Footer() +APE::Footer::Footer() : + d(new FooterPrivate()) { - d = new FooterPrivate; } -APE::Footer::Footer(const ByteVector &data) +APE::Footer::Footer(const ByteVector &data) : + d(new FooterPrivate()) { - d = new FooterPrivate; parse(data); } @@ -94,7 +91,7 @@ delete d; } -TagLib::uint APE::Footer::version() const +unsigned int APE::Footer::version() const { return d->version; } @@ -119,30 +116,30 @@ d->headerPresent = b; } -TagLib::uint APE::Footer::itemCount() const +unsigned int APE::Footer::itemCount() const { return d->itemCount; } -void APE::Footer::setItemCount(uint s) +void APE::Footer::setItemCount(unsigned int s) { d->itemCount = s; } -TagLib::uint APE::Footer::tagSize() const +unsigned int APE::Footer::tagSize() const { return d->tagSize; } -TagLib::uint APE::Footer::completeTagSize() const +unsigned int APE::Footer::completeTagSize() const { if(d->headerPresent) - return d->tagSize + d->size; + return d->tagSize + size(); else return d->tagSize; } -void APE::Footer::setTagSize(uint s) +void APE::Footer::setTagSize(unsigned int s) { d->tagSize = s; } @@ -154,13 +151,14 @@ ByteVector APE::Footer::renderFooter() const { - return render(false); + return render(false); } ByteVector APE::Footer::renderHeader() const { - if (!d->headerPresent) return ByteVector(); - + if(!d->headerPresent) + return ByteVector(); + else return render(true); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apefooter.h clementine-1.3.1-218/3rdparty/taglib/ape/apefooter.h --- clementine-1.3.1-217/3rdparty/taglib/ape/apefooter.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apefooter.h 2016-07-19 15:25:23.000000000 +0000 @@ -64,7 +64,7 @@ /*! * Returns the version number. (Note: This is the 1000 or 2000.) */ - uint version() const; + unsigned int version() const; /*! * Returns true if a header is present in the tag. @@ -89,13 +89,13 @@ /*! * Returns the number of items in the tag. */ - uint itemCount() const; + unsigned int itemCount() const; /*! * Set the item count to \a s. * \see itemCount() */ - void setItemCount(uint s); + void setItemCount(unsigned int s); /*! * Returns the tag size in bytes. This is the size of the frame content and footer. @@ -103,7 +103,7 @@ * * \see completeTagSize() */ - uint tagSize() const; + unsigned int tagSize() const; /*! * Returns the tag size, including if present, the header @@ -111,18 +111,18 @@ * * \see tagSize() */ - uint completeTagSize() const; + unsigned int completeTagSize() const; /*! * Set the tag size to \a s. * \see tagSize() */ - void setTagSize(uint s); + void setTagSize(unsigned int s); /*! * Returns the size of the footer. Presently this is always 32 bytes. */ - static uint size(); + static unsigned int size(); /*! * Returns the string used to identify an APE tag inside of a file. diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apeitem.cpp clementine-1.3.1-218/3rdparty/taglib/ape/apeitem.cpp --- clementine-1.3.1-217/3rdparty/taglib/ape/apeitem.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apeitem.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -34,7 +34,9 @@ class APE::Item::ItemPrivate { public: - ItemPrivate() : type(Text), readOnly(false) {} + ItemPrivate() : + type(Text), + readOnly(false) {} Item::ItemTypes type; String key; @@ -43,40 +45,45 @@ bool readOnly; }; -APE::Item::Item() +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +APE::Item::Item() : + d(new ItemPrivate()) { - d = new ItemPrivate; } -APE::Item::Item(const String &key, const String &value) +APE::Item::Item(const String &key, const String &value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->key = key; d->text.append(value); } -APE::Item::Item(const String &key, const StringList &values) +APE::Item::Item(const String &key, const StringList &values) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->key = key; d->text = values; } -APE::Item::Item(const String &key, const ByteVector &value, bool binary) +APE::Item::Item(const String &key, const ByteVector &value, bool binary) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->key = key; if(binary) { d->type = Binary; d->value = value; } - else + else { d->text.append(value); + } } -APE::Item::Item(const Item &item) +APE::Item::Item(const Item &item) : + d(new ItemPrivate(*item.d)) { - d = new ItemPrivate(*item.d); } APE::Item::~Item() @@ -86,13 +93,17 @@ Item &APE::Item::operator=(const Item &item) { - if(&item != this) { - delete d; - d = new ItemPrivate(*item.d); - } + 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) { d->readOnly = readOnly; @@ -173,11 +184,10 @@ int APE::Item::size() const { - // SFB: Why is d->key.size() used when size() returns the length in UniChars and not UTF-8? - int result = 8 + d->key.size() /* d->key.data(String::UTF8).size() */ + 1; - switch (d->type) { + int result = 8 + d->key.size() + 1; + switch(d->type) { case Text: - if(d->text.size()) { + if(!d->text.isEmpty()) { StringList::ConstIterator it = d->text.begin(); result += it->data(String::UTF8).size(); @@ -210,7 +220,7 @@ if(d->type == Text && !isEmpty()) return d->text.front(); else - return String::null; + return String(); } bool APE::Item::isEmpty() const @@ -239,17 +249,20 @@ return; } - const uint valueLength = data.toUInt(0, false); - const uint flags = data.toUInt(4, false); + const unsigned int valueLength = data.toUInt(0, false); + const unsigned int flags = data.toUInt(4, false); + + // An item key can contain ASCII characters from 0x20 up to 0x7E, not UTF-8. + // We assume that the validity of the given key has been checked. - d->key = String(data.mid(8), String::UTF8); + d->key = String(&data[8], String::Latin1); const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength); setReadOnly(flags & 1); setType(ItemTypes((flags >> 1) & 3)); - if(Text == d->type) + if(Text == d->type) d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8); else d->value = value; @@ -258,7 +271,7 @@ ByteVector APE::Item::render() const { ByteVector data; - TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); + unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); ByteVector value; if(isEmpty()) @@ -280,7 +293,7 @@ data.append(ByteVector::fromUInt(value.size(), false)); data.append(ByteVector::fromUInt(flags, false)); - data.append(d->key.data(String::UTF8)); + data.append(d->key.data(String::Latin1)); data.append(ByteVector('\0')); data.append(value); diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apeitem.h clementine-1.3.1-218/3rdparty/taglib/ape/apeitem.h --- clementine-1.3.1-217/3rdparty/taglib/ape/apeitem.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apeitem.h 2016-07-19 15:25:23.000000000 +0000 @@ -91,6 +91,11 @@ Item &operator=(const Item &item); /*! + * Exchanges the content of this item by the content of \a item. + */ + void swap(Item &item); + + /*! * Returns the key. */ String key() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apeproperties.cpp clementine-1.3.1-218/3rdparty/taglib/ape/apeproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/ape/apeproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apeproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -56,7 +56,7 @@ int channels; int version; int bitsPerSample; - uint sampleFrames; + unsigned int sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// @@ -122,7 +122,7 @@ return d->bitsPerSample; } -TagLib::uint APE::Properties::sampleFrames() const +unsigned int APE::Properties::sampleFrames() const { return d->sampleFrames; } @@ -133,7 +133,7 @@ namespace { - inline int headerVersion(const ByteVector &header) + int headerVersion(const ByteVector &header) { if(header.size() < 6 || !header.startsWith("MAC ")) return -1; @@ -184,7 +184,7 @@ return; } - const uint descriptorBytes = descriptor.toUInt(0, false); + const unsigned int descriptorBytes = descriptor.toUInt(0, false); if((descriptorBytes - 52) > 0) file->seek(descriptorBytes - 52, File::Current); @@ -201,12 +201,12 @@ d->sampleRate = header.toUInt(20, false); d->bitsPerSample = header.toShort(16, false); - const uint totalFrames = header.toUInt(12, false); + const unsigned int totalFrames = header.toUInt(12, false); if(totalFrames == 0) return; - const uint blocksPerFrame = header.toUInt(4, false); - const uint finalFrameBlocks = header.toUInt(8, false); + const unsigned int blocksPerFrame = header.toUInt(4, false); + const unsigned int finalFrameBlocks = header.toUInt(8, false); d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks; } @@ -218,14 +218,14 @@ return; } - const uint totalFrames = header.toUInt(18, false); + const unsigned int totalFrames = header.toUInt(18, false); // Fail on 0 length APE files (catches non-finalized APE files) if(totalFrames == 0) return; const short compressionLevel = header.toShort(0, false); - uint blocksPerFrame; + unsigned int blocksPerFrame; if(d->version >= 3950) blocksPerFrame = 73728 * 4; else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000)) @@ -237,7 +237,7 @@ d->channels = header.toShort(4, false); d->sampleRate = header.toUInt(6, false); - const uint finalFrameBlocks = header.toUInt(22, false); + const unsigned int finalFrameBlocks = header.toUInt(22, false); d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks; // Get the bit depth from the RIFF-fmt chunk. diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apeproperties.h clementine-1.3.1-218/3rdparty/taglib/ape/apeproperties.h --- clementine-1.3.1-217/3rdparty/taglib/ape/apeproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apeproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -118,7 +118,7 @@ /*! * Returns the total number of audio samples in file. */ - uint sampleFrames() const; + unsigned int sampleFrames() const; /*! * Returns APE version. diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apetag.cpp clementine-1.3.1-218/3rdparty/taglib/ape/apetag.cpp --- clementine-1.3.1-217/3rdparty/taglib/ape/apetag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apetag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,7 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef __SUNPRO_CC +#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130) // Sun Studio finds multiple specializations of Map because // it considers specializations with and without class types // to be different; this define forces Map to use only the @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include "apetag.h" #include "apefooter.h" @@ -43,18 +45,43 @@ using namespace TagLib; using namespace APE; +namespace +{ + bool isKeyValid(const char *key, size_t length) + { + const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 }; + + if(length < 2 || length > 255) + return false; + + // only allow printable ASCII including space (32..126) + + for(const char *p = key; p < key + length; ++p) { + const int c = static_cast(*p); + if(c < 32 || c > 126) + return false; + } + + for(size_t i = 0; invalidKeys[i] != 0; ++i) { + if(Utils::equalsIgnoreCase(key, invalidKeys[i])) + return false; + } + + return true; + } +} + class APE::Tag::TagPrivate { public: TagPrivate() : file(0), - footerLocation(-1) {} + footerLocation(0) {} - TagLib::File *file; + File *file; long footerLocation; Footer footer; - ItemListMap itemListMap; }; @@ -91,46 +118,46 @@ String APE::Tag::title() const { if(d->itemListMap["TITLE"].isEmpty()) - return String::null; + return String(); return d->itemListMap["TITLE"].values().toString(); } String APE::Tag::artist() const { if(d->itemListMap["ARTIST"].isEmpty()) - return String::null; + return String(); return d->itemListMap["ARTIST"].values().toString(); } String APE::Tag::album() const { if(d->itemListMap["ALBUM"].isEmpty()) - return String::null; + return String(); return d->itemListMap["ALBUM"].values().toString(); } String APE::Tag::comment() const { if(d->itemListMap["COMMENT"].isEmpty()) - return String::null; + return String(); return d->itemListMap["COMMENT"].values().toString(); } String APE::Tag::genre() const { if(d->itemListMap["GENRE"].isEmpty()) - return String::null; + return String(); return d->itemListMap["GENRE"].values().toString(); } -TagLib::uint APE::Tag::year() const +unsigned int APE::Tag::year() const { if(d->itemListMap["YEAR"].isEmpty()) return 0; return d->itemListMap["YEAR"].toString().toInt(); } -TagLib::uint APE::Tag::track() const +unsigned int APE::Tag::track() const { if(d->itemListMap["TRACK"].isEmpty()) return 0; @@ -162,7 +189,7 @@ addValue("GENRE", s, true); } -void APE::Tag::setYear(uint i) +void APE::Tag::setYear(unsigned int i) { if(i <= 0) removeItem("YEAR"); @@ -170,7 +197,7 @@ addValue("YEAR", String::number(i), true); } -void APE::Tag::setTrack(uint i) +void APE::Tag::setTrack(unsigned int i) { if(i <= 0) removeItem("TRACK"); @@ -178,14 +205,18 @@ addValue("TRACK", String::number(i), true); } -// conversions of tag keys between what we use in PropertyMap and what's usual -// for APE tags -static const TagLib::uint keyConversionsSize = 5; //usual, APE -static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" }, - {"DATE", "YEAR" }, - {"ALBUMARTIST", "ALBUM ARTIST"}, - {"DISCNUMBER", "DISC" }, - {"REMIXER", "MIXARTIST" }}; +namespace +{ + // conversions of tag keys between what we use in PropertyMap and what's usual + // for APE tags + // usual, APE + const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" }, + {"DATE", "YEAR" }, + {"ALBUMARTIST", "ALBUM ARTIST"}, + {"DISCNUMBER", "DISC" }, + {"REMIXER", "MIXARTIST" }}; + const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]); +} PropertyMap APE::Tag::properties() const { @@ -195,14 +226,16 @@ String tagName = it->first.upper(); // if the item is Binary or Locator, or if the key is an invalid string, // add to unsupportedData - if(it->second.type() != Item::Text || tagName.isNull()) + if(it->second.type() != Item::Text || tagName.isEmpty()) { properties.unsupportedData().append(it->first); + } else { // Some tags need to be handled specially - for(uint i = 0; i < keyConversionsSize; ++i) + for(size_t i = 0; i < keyConversionsSize; ++i) { if(tagName == keyConversions[i][1]) tagName = keyConversions[i][0]; - properties[tagName].append(it->second.toStringList()); + } + properties[tagName].append(it->second.toStringList()); } } return properties; @@ -220,7 +253,7 @@ PropertyMap properties(origProps); // make a local copy that can be modified // see comment in properties() - for(uint i = 0; i < keyConversionsSize; ++i) + for(size_t i = 0; i < keyConversionsSize; ++i) if(properties.contains(keyConversions[i][0])) { properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]); properties.erase(keyConversions[i][0]); @@ -232,7 +265,7 @@ for(; remIt != itemListMap().end(); ++remIt) { String key = remIt->first.upper(); // only remove if a) key is valid, b) type is text, c) key not contained in new properties - if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key)) + if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key)) toRemove.append(remIt->first); } @@ -247,7 +280,7 @@ if(!checkKey(tagName)) invalid.insert(it->first, it->second); else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) { - if(it->second.size() == 0) + if(it->second.isEmpty()) removeItem(tagName); else { StringList::ConstIterator valueIt = it->second.begin(); @@ -263,16 +296,11 @@ bool APE::Tag::checkKey(const String &key) { - if(key.size() < 2 || key.size() > 16) - return false; - for(String::ConstIterator it = key.begin(); it != key.end(); it++) - // only allow printable ASCII including space (32..127) - if (*it < 32 || *it >= 128) - return false; - String upperKey = key.upper(); - if (upperKey=="ID3" || upperKey=="TAG" || upperKey=="OGGS" || upperKey=="MP+") - return false; - return true; + if(!key.isLatin1()) + return false; + + const std::string data = key.to8Bit(false); + return isKeyValid(data.c_str(), data.size()); } APE::Footer *APE::Tag::footer() const @@ -294,31 +322,39 @@ { if(replace) removeItem(key); - if(!key.isEmpty() && !value.isEmpty()) { - if(!replace && d->itemListMap.contains(key)) { - // Text items may contain more than one value - if(APE::Item::Text == d->itemListMap.begin()->second.type()) - d->itemListMap[key.upper()].appendValue(value); - // Binary or locator items may have only one value - else - setItem(key, Item(key, value)); - } - else - setItem(key, Item(key, value)); - } + + if(value.isEmpty()) + return; + + // Text items may contain more than one value. + // Binary or locator items may have only one value, hence always replaced. + + ItemListMap::Iterator it = d->itemListMap.find(key.upper()); + + if(it != d->itemListMap.end() && it->second.type() == Item::Text) + it->second.appendValue(value); + else + setItem(key, Item(key, value)); } void APE::Tag::setData(const String &key, const ByteVector &value) { removeItem(key); - if(!key.isEmpty() && !value.isEmpty()) - setItem(key, Item(key, value, true)); + + if(value.isEmpty()) + return; + + setItem(key, Item(key, value, true)); } void APE::Tag::setItem(const String &key, const Item &item) { - if(!key.isEmpty()) - d->itemListMap.insert(key.upper(), 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 @@ -338,7 +374,7 @@ d->footer.setData(d->file->readBlock(Footer::size())); if(d->footer.tagSize() <= Footer::size() || - d->footer.tagSize() > uint(d->file->length())) + d->footer.tagSize() > static_cast(d->file->length())) return; d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize()); @@ -349,15 +385,11 @@ ByteVector APE::Tag::render() const { ByteVector data; - uint itemCount = 0; + unsigned int itemCount = 0; - { - for(Map::ConstIterator it = d->itemListMap.begin(); - it != d->itemListMap.end(); ++it) - { - data.append(it->second.render()); - itemCount++; - } + for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) { + data.append(it->second.render()); + itemCount++; } d->footer.setItemCount(itemCount); @@ -374,14 +406,29 @@ if(data.size() < 11) return; - uint pos = 0; + unsigned int pos = 0; - for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) { - APE::Item item; - item.parse(data.mid(pos)); + for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) { + + const int nullPos = data.find('\0', pos + 8); + if(nullPos < 0) { + debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing."); + return; + } - d->itemListMap.insert(item.key().upper(), item); + const unsigned int keyLength = nullPos - pos - 8; + const unsigned int valLegnth = data.toUInt(pos, false); + + if(isKeyValid(&data[pos + 8], keyLength)){ + APE::Item item; + item.parse(data.mid(pos)); + + d->itemListMap.insert(item.key().upper(), item); + } + else { + debug("APE::Tag::parse() - Skipped an item due to an invalid key."); + } - pos += item.size(); + pos += keyLength + valLegnth + 9; } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/ape/apetag.h clementine-1.3.1-218/3rdparty/taglib/ape/apetag.h --- clementine-1.3.1-217/3rdparty/taglib/ape/apetag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ape/apetag.h 2016-07-19 15:25:23.000000000 +0000 @@ -92,16 +92,16 @@ virtual String album() const; virtual String comment() const; virtual String genre() const; - virtual uint year() const; - virtual uint track() const; + virtual unsigned int year() const; + virtual unsigned int track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); - virtual void setYear(uint i); - virtual void setTrack(uint i); + virtual void setYear(unsigned int i); + virtual void setTrack(unsigned int i); /*! * Implements the unified tag dictionary interface -- export function. diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asfattribute.cpp clementine-1.3.1-218/3rdparty/taglib/asf/asfattribute.cpp --- clementine-1.3.1-217/3rdparty/taglib/asf/asfattribute.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asfattribute.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -58,84 +58,86 @@ // public members //////////////////////////////////////////////////////////////////////////////// -ASF::Attribute::Attribute() +ASF::Attribute::Attribute() : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = UnicodeType; } -ASF::Attribute::Attribute(const ASF::Attribute &other) - : d(other.d) +ASF::Attribute::Attribute(const ASF::Attribute &other) : + d(other.d) { d->ref(); } -ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) -{ - if(&other != this) { - if(d->deref()) - delete d; - d = other.d; - d->ref(); - } - return *this; -} - -ASF::Attribute::~Attribute() +ASF::Attribute::Attribute(const String &value) : + d(new AttributePrivate()) { - if(d->deref()) - delete d; -} - -ASF::Attribute::Attribute(const String &value) -{ - d = new AttributePrivate; d->type = UnicodeType; d->stringValue = value; } -ASF::Attribute::Attribute(const ByteVector &value) +ASF::Attribute::Attribute(const ByteVector &value) : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = BytesType; d->byteVectorValue = value; } -ASF::Attribute::Attribute(const ASF::Picture &value) +ASF::Attribute::Attribute(const ASF::Picture &value) : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = BytesType; d->pictureValue = value; } -ASF::Attribute::Attribute(unsigned int value) +ASF::Attribute::Attribute(unsigned int value) : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = DWordType; d->intValue = value; } -ASF::Attribute::Attribute(unsigned long long value) +ASF::Attribute::Attribute(unsigned long long value) : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = QWordType; d->longLongValue = value; } -ASF::Attribute::Attribute(unsigned short value) +ASF::Attribute::Attribute(unsigned short value) : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = WordType; d->shortValue = value; } -ASF::Attribute::Attribute(bool value) +ASF::Attribute::Attribute(bool value) : + d(new AttributePrivate()) { - d = new AttributePrivate; d->type = BoolType; d->boolValue = value; } +ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) +{ + Attribute(other).swap(*this); + return *this; +} + +void ASF::Attribute::swap(Attribute &other) +{ + using std::swap; + + swap(d, other.d); +} + +ASF::Attribute::~Attribute() +{ + if(d->deref()) + delete d; +} + ASF::Attribute::AttributeTypes ASF::Attribute::type() const { return d->type; @@ -180,7 +182,7 @@ String ASF::Attribute::parse(ASF::File &f, int kind) { - uint size, nameLength; + unsigned int size, nameLength; String name; d->pictureValue = Picture::fromInvalid(); // extended content descriptor @@ -351,4 +353,3 @@ { d->stream = value; } - diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asfattribute.h clementine-1.3.1-218/3rdparty/taglib/asf/asfattribute.h --- clementine-1.3.1-217/3rdparty/taglib/asf/asfattribute.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asfattribute.h 2016-07-19 15:25:23.000000000 +0000 @@ -116,6 +116,11 @@ ASF::Attribute &operator=(const Attribute &other); /*! + * Exchanges the content of the Attribute by the content of \a other. + */ + void swap(Attribute &other); + + /*! * Destroys the attribute. */ virtual ~Attribute(); diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asffile.cpp clementine-1.3.1-218/3rdparty/taglib/asf/asffile.cpp --- clementine-1.3.1-217/3rdparty/taglib/asf/asffile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asffile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -50,7 +50,7 @@ class MetadataLibraryObject; FilePrivate(): - size(0), + headerSize(0), tag(0), properties(0), contentDescriptionObject(0), @@ -68,7 +68,7 @@ delete properties; } - unsigned long long size; + unsigned long long headerSize; ASF::Tag *tag; ASF::Properties *properties; @@ -120,21 +120,21 @@ { public: ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); }; class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject { public: ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); }; class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject { public: ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); ByteVector render(ASF::File *file); }; @@ -143,7 +143,7 @@ public: ByteVectorList attributeData; ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); ByteVector render(ASF::File *file); }; @@ -152,7 +152,7 @@ public: ByteVectorList attributeData; ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); ByteVector render(ASF::File *file); }; @@ -161,7 +161,7 @@ public: ByteVectorList attributeData; ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); ByteVector render(ASF::File *file); }; @@ -171,7 +171,7 @@ List objects; HeaderExtensionObject(); ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); ByteVector render(ASF::File *file); }; @@ -179,7 +179,7 @@ { public: ByteVector guid() const; - void parse(ASF::File *file, uint size); + void parse(ASF::File *file, unsigned int size); private: enum CodecType @@ -196,7 +196,7 @@ if(size > 24 && size <= (unsigned int)(file->length())) data = file->readBlock(size - 24); else - data = ByteVector::null; + data = ByteVector(); } ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/) @@ -218,7 +218,7 @@ return filePropertiesGuid; } -void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, uint size) +void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size) { BaseObject::parse(file, size); if(data.size() < 64) { @@ -236,7 +236,7 @@ return streamPropertiesGuid; } -void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, uint size) +void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size) { BaseObject::parse(file, size); if(data.size() < 70) { @@ -256,7 +256,7 @@ return contentDescriptionGuid; } -void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/) +void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) { file->d->contentDescriptionObject = this; const int titleLength = readWORD(file); @@ -297,7 +297,7 @@ return extendedContentDescriptionGuid; } -void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/) +void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) { file->d->extendedContentDescriptionObject = this; int count = readWORD(file); @@ -312,7 +312,7 @@ { data.clear(); data.append(ByteVector::fromShort(attributeData.size(), false)); - data.append(attributeData.toByteVector(ByteVector::null)); + data.append(attributeData.toByteVector("")); return BaseObject::render(file); } @@ -321,7 +321,7 @@ return metadataGuid; } -void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, uint /*size*/) +void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/) { file->d->metadataObject = this; int count = readWORD(file); @@ -336,7 +336,7 @@ { data.clear(); data.append(ByteVector::fromShort(attributeData.size(), false)); - data.append(attributeData.toByteVector(ByteVector::null)); + data.append(attributeData.toByteVector("")); return BaseObject::render(file); } @@ -345,7 +345,7 @@ return metadataLibraryGuid; } -void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/) +void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/) { file->d->metadataLibraryObject = this; int count = readWORD(file); @@ -360,7 +360,7 @@ { data.clear(); data.append(ByteVector::fromShort(attributeData.size(), false)); - data.append(attributeData.toByteVector(ByteVector::null)); + data.append(attributeData.toByteVector("")); return BaseObject::render(file); } @@ -374,7 +374,7 @@ return headerExtensionGuid; } -void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/) +void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/) { file->d->headerExtensionObject = this; file->seek(18, File::Current); @@ -423,7 +423,7 @@ return codecListGuid; } -void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, uint size) +void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size) { BaseObject::parse(file, size); if(data.size() <= 20) { @@ -431,7 +431,7 @@ return; } - uint pos = 16; + unsigned int pos = 16; const int count = data.toUInt(pos, false); pos += 4; @@ -447,13 +447,13 @@ int nameLength = data.toUShort(pos, false); pos += 2; - const uint namePos = pos; + const unsigned int namePos = pos; pos += nameLength * 2; const int descLength = data.toUShort(pos, false); pos += 2; - const uint descPos = pos; + const unsigned int descPos = pos; pos += descLength * 2; const int infoLength = data.toUShort(pos, false); @@ -556,6 +556,10 @@ d->headerExtensionObject->objects.append(d->metadataLibraryObject); } + d->extendedContentDescriptionObject->attributeData.clear(); + d->metadataObject->attributeData.clear(); + d->metadataLibraryObject->attributeData.clear(); + const AttributeListMap allAttributes = d->tag->attributeListMap(); for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) { @@ -591,8 +595,14 @@ data.append((*it)->render(this)); } - data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data; - insert(data, 0, (TagLib::ulong)d->size); + seek(16); + writeBlock(ByteVector::fromLongLong(data.size() + 30, false)); + writeBlock(ByteVector::fromUInt(d->objects.size(), false)); + writeBlock(ByteVector("\x01\x02", 2)); + + insert(data, 30, static_cast(d->headerSize - 30)); + + d->headerSize = data.size() + 30; return true; } @@ -617,7 +627,7 @@ d->properties = new ASF::Properties(); bool ok; - d->size = readQWORD(this, &ok); + d->headerSize = readQWORD(this, &ok); if(!ok) { setValid(false); return; diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asffile.h clementine-1.3.1-218/3rdparty/taglib/asf/asffile.h --- clementine-1.3.1-217/3rdparty/taglib/asf/asffile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asffile.h 2016-07-19 15:25:23.000000000 +0000 @@ -112,9 +112,6 @@ * Save the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ virtual bool save(); diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asfpicture.cpp clementine-1.3.1-218/3rdparty/taglib/asf/asfpicture.cpp --- clementine-1.3.1-217/3rdparty/taglib/asf/asfpicture.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asfpicture.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -48,14 +48,14 @@ // Picture class members //////////////////////////////////////////////////////////////////////////////// -ASF::Picture::Picture() +ASF::Picture::Picture() : + d(new PicturePrivate()) { - d = new PicturePrivate(); d->valid = true; } -ASF::Picture::Picture(const Picture& other) - : d(other.d) +ASF::Picture::Picture(const Picture& other) : + d(other.d) { d->ref(); } @@ -120,19 +120,22 @@ ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other) { - if(other.d != d) { - if(d->deref()) - delete d; - d = other.d; - d->ref(); - } + Picture(other).swap(*this); return *this; } +void ASF::Picture::swap(Picture &other) +{ + using std::swap; + + swap(d, other.d); +} + ByteVector ASF::Picture::render() const { if(!isValid()) - return ByteVector::null; + return ByteVector(); + return ByteVector((char)d->type) + ByteVector::fromUInt(d->picture.size(), false) + @@ -148,7 +151,7 @@ return; int pos = 0; d->type = (Type)bytes[0]; ++pos; - const uint dataLen = bytes.toUInt(pos, false); pos+=4; + const unsigned int dataLen = bytes.toUInt(pos, false); pos+=4; const ByteVector nullStringTerminator(2, 0); @@ -178,4 +181,3 @@ ret.d->valid = false; return ret; } - diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asfpicture.h clementine-1.3.1-218/3rdparty/taglib/asf/asfpicture.h --- clementine-1.3.1-217/3rdparty/taglib/asf/asfpicture.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asfpicture.h 2016-07-19 15:25:23.000000000 +0000 @@ -118,6 +118,11 @@ Picture& operator=(const Picture& other); /*! + * Exchanges the content of the Picture by the content of \a other. + */ + void swap(Picture &other); + + /*! * Returns true if Picture stores valid picture */ bool isValid() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asftag.cpp clementine-1.3.1-218/3rdparty/taglib/asf/asftag.cpp --- clementine-1.3.1-217/3rdparty/taglib/asf/asftag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asftag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -64,7 +64,7 @@ { if(d->attributeListMap.contains("WM/AlbumTitle")) return d->attributeListMap["WM/AlbumTitle"][0].toString(); - return String::null; + return String(); } String ASF::Tag::copyright() const @@ -107,7 +107,7 @@ { if(d->attributeListMap.contains("WM/Genre")) return d->attributeListMap["WM/Genre"][0].toString(); - return String::null; + return String(); } void ASF::Tag::setTitle(const String &value) @@ -145,12 +145,12 @@ setAttribute("WM/Genre", value); } -void ASF::Tag::setYear(uint value) +void ASF::Tag::setYear(unsigned int value) { setAttribute("WM/Year", String::number(value)); } -void ASF::Tag::setTrack(uint value) +void ASF::Tag::setTrack(unsigned int value) { setAttribute("WM/TrackNumber", String::number(value)); } @@ -210,58 +210,64 @@ d->attributeListMap.isEmpty(); } -static const char *keyTranslation[][2] = { - { "WM/AlbumTitle", "ALBUM" }, - { "WM/AlbumArtist", "ALBUMARTIST" }, - { "WM/Composer", "COMPOSER" }, - { "WM/Writer", "WRITER" }, - { "WM/Conductor", "CONDUCTOR" }, - { "WM/ModifiedBy", "REMIXER" }, - { "WM/Year", "DATE" }, - { "WM/OriginalReleaseYear", "ORIGINALDATE" }, - { "WM/Producer", "PRODUCER" }, - { "WM/ContentGroupDescription", "GROUPING" }, - { "WM/SubTitle", "SUBTITLE" }, - { "WM/SetSubTitle", "DISCSUBTITLE" }, - { "WM/TrackNumber", "TRACKNUMBER" }, - { "WM/PartOfSet", "DISCNUMBER" }, - { "WM/Genre", "GENRE" }, - { "WM/BeatsPerMinute", "BPM" }, - { "WM/Mood", "MOOD" }, - { "WM/ISRC", "ISRC" }, - { "WM/Lyrics", "LYRICS" }, - { "WM/Media", "MEDIA" }, - { "WM/Publisher", "LABEL" }, - { "WM/CatalogNo", "CATALOGNUMBER" }, - { "WM/Barcode", "BARCODE" }, - { "WM/EncodedBy", "ENCODEDBY" }, - { "WM/AlbumSortOrder", "ALBUMSORT" }, - { "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" }, - { "WM/ArtistSortOrder", "ARTISTSORT" }, - { "WM/TitleSortOrder", "TITLESORT" }, - { "WM/Script", "SCRIPT" }, - { "WM/Language", "LANGUAGE" }, - { "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" }, - { "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" }, - { "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" }, - { "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, - { "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, - { "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" }, - { "MusicIP/PUID", "MUSICIP_PUID" }, - { "Acoustid/Id", "ACOUSTID_ID" }, - { "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" }, -}; - -PropertyMap ASF::Tag::properties() const +namespace { - static Map keyMap; - if(keyMap.isEmpty()) { - int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); - for(int i = 0; i < numKeys; i++) { - keyMap[keyTranslation[i][0]] = keyTranslation[i][1]; + const char *keyTranslation[][2] = { + { "WM/AlbumTitle", "ALBUM" }, + { "WM/AlbumArtist", "ALBUMARTIST" }, + { "WM/Composer", "COMPOSER" }, + { "WM/Writer", "WRITER" }, + { "WM/Conductor", "CONDUCTOR" }, + { "WM/ModifiedBy", "REMIXER" }, + { "WM/Year", "DATE" }, + { "WM/OriginalReleaseYear", "ORIGINALDATE" }, + { "WM/Producer", "PRODUCER" }, + { "WM/ContentGroupDescription", "GROUPING" }, + { "WM/SubTitle", "SUBTITLE" }, + { "WM/SetSubTitle", "DISCSUBTITLE" }, + { "WM/TrackNumber", "TRACKNUMBER" }, + { "WM/PartOfSet", "DISCNUMBER" }, + { "WM/Genre", "GENRE" }, + { "WM/BeatsPerMinute", "BPM" }, + { "WM/Mood", "MOOD" }, + { "WM/ISRC", "ISRC" }, + { "WM/Lyrics", "LYRICS" }, + { "WM/Media", "MEDIA" }, + { "WM/Publisher", "LABEL" }, + { "WM/CatalogNo", "CATALOGNUMBER" }, + { "WM/Barcode", "BARCODE" }, + { "WM/EncodedBy", "ENCODEDBY" }, + { "WM/AlbumSortOrder", "ALBUMSORT" }, + { "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" }, + { "WM/ArtistSortOrder", "ARTISTSORT" }, + { "WM/TitleSortOrder", "TITLESORT" }, + { "WM/Script", "SCRIPT" }, + { "WM/Language", "LANGUAGE" }, + { "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" }, + { "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" }, + { "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" }, + { "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, + { "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, + { "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" }, + { "MusicIP/PUID", "MUSICIP_PUID" }, + { "Acoustid/Id", "ACOUSTID_ID" }, + { "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" }, + }; + 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(); } +} +PropertyMap ASF::Tag::properties() const +{ PropertyMap props; if(!d->title.isEmpty()) { @@ -279,8 +285,8 @@ ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin(); for(; it != d->attributeListMap.end(); ++it) { - if(keyMap.contains(it->first)) { - String key = keyMap[it->first]; + const String key = translateKey(it->first); + if(!key.isEmpty()) { AttributeList::ConstIterator it2 = it->second.begin(); for(; it2 != it->second.end(); ++it2) { if(key == "TRACKNUMBER") { @@ -323,16 +329,16 @@ for(; it != origProps.end(); ++it) { if(!props.contains(it->first) || props[it->first].isEmpty()) { if(it->first == "TITLE") { - d->title = String::null; + d->title.clear(); } else if(it->first == "ARTIST") { - d->artist = String::null; + d->artist.clear(); } else if(it->first == "COMMENT") { - d->comment = String::null; + d->comment.clear(); } else if(it->first == "COPYRIGHT") { - d->copyright = String::null; + d->copyright.clear(); } else { d->attributeListMap.erase(reverseKeyMap[it->first]); diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asftag.h clementine-1.3.1-218/3rdparty/taglib/asf/asftag.h --- clementine-1.3.1-217/3rdparty/taglib/asf/asftag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asftag.h 2016-07-19 15:25:23.000000000 +0000 @@ -90,13 +90,13 @@ /*! * Returns the year; if there is no year set, this will return 0. */ - virtual uint year() const; + virtual unsigned int year() const; /*! * Returns the track number; if there is no track number set, this will * return 0. */ - virtual uint track() const; + virtual unsigned int track() const; /*! * Sets the title to \a s. @@ -137,12 +137,12 @@ /*! * Sets the year to \a i. If \a s is 0 then this value will be cleared. */ - virtual void setYear(uint i); + virtual void setYear(unsigned int i); /*! * Sets the track to \a i. If \a s is 0 then this value will be cleared. */ - virtual void setTrack(uint i); + virtual void setTrack(unsigned int i); /*! * Returns true if the tag does not contain any data. This should be diff -Nru clementine-1.3.1-217/3rdparty/taglib/asf/asfutils.h clementine-1.3.1-218/3rdparty/taglib/asf/asfutils.h --- clementine-1.3.1-217/3rdparty/taglib/asf/asfutils.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/asf/asfutils.h 2016-07-19 15:25:23.000000000 +0000 @@ -34,65 +34,68 @@ { namespace ASF { - - inline ushort readWORD(File *file, bool *ok = 0) + namespace { - const ByteVector v = file->readBlock(2); - if(v.size() != 2) { - if(ok) *ok = false; - return 0; - } - if(ok) *ok = true; - return v.toUShort(false); - } - inline uint readDWORD(File *file, bool *ok = 0) - { - const ByteVector v = file->readBlock(4); - if(v.size() != 4) { - if(ok) *ok = false; - return 0; + inline unsigned short readWORD(File *file, bool *ok = 0) + { + const ByteVector v = file->readBlock(2); + if(v.size() != 2) { + if(ok) *ok = false; + return 0; + } + if(ok) *ok = true; + return v.toUShort(false); } - if(ok) *ok = true; - return v.toUInt(false); - } - inline long long readQWORD(File *file, bool *ok = 0) - { - const ByteVector v = file->readBlock(8); - if(v.size() != 8) { - if(ok) *ok = false; - return 0; + inline unsigned int readDWORD(File *file, bool *ok = 0) + { + const ByteVector v = file->readBlock(4); + if(v.size() != 4) { + if(ok) *ok = false; + return 0; + } + if(ok) *ok = true; + return v.toUInt(false); } - if(ok) *ok = true; - return v.toLongLong(false); - } - inline String readString(File *file, int length) - { - ByteVector data = file->readBlock(length); - unsigned int size = data.size(); - while (size >= 2) { - if(data[size - 1] != '\0' || data[size - 2] != '\0') { - break; + inline long long readQWORD(File *file, bool *ok = 0) + { + const ByteVector v = file->readBlock(8); + if(v.size() != 8) { + if(ok) *ok = false; + return 0; } - size -= 2; + if(ok) *ok = true; + return v.toLongLong(false); } - if(size != data.size()) { - data.resize(size); + + inline String readString(File *file, int length) + { + ByteVector data = file->readBlock(length); + unsigned int size = data.size(); + while (size >= 2) { + if(data[size - 1] != '\0' || data[size - 2] != '\0') { + break; + } + size -= 2; + } + if(size != data.size()) { + data.resize(size); + } + return String(data, String::UTF16LE); } - return String(data, String::UTF16LE); - } - inline ByteVector renderString(const String &str, bool includeLength = false) - { - ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false); - if(includeLength) { - data = ByteVector::fromShort(data.size(), false) + data; + inline ByteVector renderString(const String &str, bool includeLength = false) + { + ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false); + if(includeLength) { + data = ByteVector::fromShort(data.size(), false) + data; + } + return data; } - return data; - } + } } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/audioproperties.cpp clementine-1.3.1-218/3rdparty/taglib/audioproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/audioproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/audioproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -57,7 +57,7 @@ } -int TagLib::AudioProperties::lengthInSeconds() const +int AudioProperties::lengthInSeconds() const { // This is an ugly workaround but we can't add a virtual function. // Should be virtual in taglib2. @@ -105,7 +105,7 @@ return 0; } -int TagLib::AudioProperties::lengthInMilliseconds() const +int AudioProperties::lengthInMilliseconds() const { // This is an ugly workaround but we can't add a virtual function. // Should be virtual in taglib2. diff -Nru clementine-1.3.1-217/3rdparty/taglib/CMakeLists.txt clementine-1.3.1-218/3rdparty/taglib/CMakeLists.txt --- clementine-1.3.1-217/3rdparty/taglib/CMakeLists.txt 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/CMakeLists.txt 2016-07-19 15:25:23.000000000 +0000 @@ -1,8 +1,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-delete-non-virtual-dtor") -set(TAGLIB_SOVERSION_CURRENT 16) -set(TAGLIB_SOVERSION_REVISION 1) -set(TAGLIB_SOVERSION_AGE 15) +set(TAGLIB_SOVERSION_CURRENT 17) +set(TAGLIB_SOVERSION_REVISION 0) +set(TAGLIB_SOVERSION_AGE 16) + math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}") math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}") math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}") @@ -52,6 +53,10 @@ include_directories(${ZLIB_SOURCE}) endif() +if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC OR HAVE_BOOST_ZLIB) + include_directories(${Boost_INCLUDE_DIR}) +endif() + set(tag_HDRS tag.h fileref.h @@ -103,6 +108,7 @@ mpeg/id3v2/frames/urllinkframe.h mpeg/id3v2/frames/chapterframe.h mpeg/id3v2/frames/tableofcontentsframe.h + mpeg/id3v2/frames/podcastframe.h ogg/oggfile.h ogg/oggpage.h ogg/oggpageheader.h @@ -197,6 +203,7 @@ mpeg/id3v2/frames/urllinkframe.cpp mpeg/id3v2/frames/chapterframe.cpp mpeg/id3v2/frames/tableofcontentsframe.cpp + mpeg/id3v2/frames/podcastframe.cpp ) set(ogg_SRCS @@ -323,6 +330,7 @@ toolkit/tpropertymap.cpp toolkit/trefcounter.cpp toolkit/tdebuglistener.cpp + toolkit/tzlib.cpp ) if(NOT WIN32) @@ -352,6 +360,7 @@ tagunion.cpp fileref.cpp audioproperties.cpp + tagutils.cpp ) add_library(tag STATIC ${tag_LIB_SRCS} ${tag_HDRS}) @@ -360,6 +369,14 @@ target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() +if(HAVE_BOOST_ATOMIC) + target_link_libraries(tag ${Boost_ATOMIC_LIBRARY}) +endif() + +if(HAVE_BOOST_ZLIB) + target_link_libraries(tag ${Boost_IOSTREAMS_LIBRARY} ${Boost_ZLIB_LIBRARY}) +endif() + set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} diff -Nru clementine-1.3.1-217/3rdparty/taglib/fileref.cpp clementine-1.3.1-218/3rdparty/taglib/fileref.cpp --- clementine-1.3.1-217/3rdparty/taglib/fileref.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/fileref.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -30,7 +30,7 @@ #include #include #include -#include "trefcounter.h" +#include #include "fileref.h" #include "asffile.h" @@ -54,41 +54,176 @@ using namespace TagLib; +namespace +{ + typedef List ResolverList; + ResolverList fileTypeResolvers; + + // Templatized internal functions. T should be String or IOStream*. + + template + FileName toFileName(T arg) + { + debug("FileRef::toFileName(): This version should never be called."); + return FileName(L""); + } + + template <> + FileName toFileName(IOStream *arg) + { + return arg->name(); + } + + template <> + FileName toFileName(FileName arg) + { + return arg; + } + + template + File *resolveFileType(T arg, bool readProperties, + AudioProperties::ReadStyle style) + { + debug("FileRef::resolveFileType(): This version should never be called."); + return 0; + } + + template <> + File *resolveFileType(IOStream *arg, bool readProperties, + AudioProperties::ReadStyle style) + { + return 0; + } + + template <> + File *resolveFileType(FileName arg, bool readProperties, + AudioProperties::ReadStyle style) + { + ResolverList::ConstIterator it = fileTypeResolvers.begin(); + for(; it != fileTypeResolvers.end(); ++it) { + File *file = (*it)->createFile(arg, readProperties, style); + if(file) + return file; + } + + return 0; + } + + template + File* createInternal(T arg, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { + File *file = resolveFileType(arg, readAudioProperties, audioPropertiesStyle); + if(file) + return file; + +#ifdef _WIN32 + const String s = toFileName(arg).toString(); +#else + const String s(toFileName(arg)); +#endif + + String ext; + const int pos = s.rfind("."); + if(pos != -1) + ext = s.substr(pos + 1).upper(); + + // If this list is updated, the method defaultFileExtensions() should also be + // updated. However at some point that list should be created at the same time + // that a default file type resolver is created. + + if(ext.isEmpty()) + return 0; + + if(ext == "MP3") + return new MPEG::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + if(ext == "OGG") + return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "OGA") { + /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ + File *file = new Ogg::FLAC::File(arg, readAudioProperties, audioPropertiesStyle); + if(file->isValid()) + return file; + delete file; + return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle); + } + if(ext == "FLAC") + return new FLAC::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + if(ext == "MPC") + return new MPC::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "WV") + return new WavPack::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "SPX") + return new Ogg::Speex::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "OPUS") + return new Ogg::Opus::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "TTA") + return new TrueAudio::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V") + return new MP4::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "WMA" || ext == "ASF") + return new ASF::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") + return new RIFF::AIFF::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "WAV") + return new RIFF::WAV::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "APE") + return new APE::File(arg, readAudioProperties, audioPropertiesStyle); + // module, nst and wow are possible but uncommon extensions + if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") + return new Mod::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "S3M") + return new S3M::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "IT") + return new IT::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "XM") + return new XM::File(arg, readAudioProperties, audioPropertiesStyle); + + return 0; + } +} + class FileRef::FileRefPrivate : public RefCounter { public: - FileRefPrivate(File *f) : RefCounter(), file(f) {} + FileRefPrivate(File *f) : + RefCounter(), + file(f) {} + ~FileRefPrivate() { delete file; } File *file; - static List fileTypeResolvers; }; -List FileRef::FileRefPrivate::fileTypeResolvers; - //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -FileRef::FileRef() +FileRef::FileRef() : + d(new FileRefPrivate(0)) { - d = new FileRefPrivate(0); } FileRef::FileRef(FileName fileName, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) + AudioProperties::ReadStyle audioPropertiesStyle) : + d(new FileRefPrivate(createInternal(fileName, readAudioProperties, audioPropertiesStyle))) +{ +} + +FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : + d(new FileRefPrivate(createInternal(stream, readAudioProperties, audioPropertiesStyle))) { - d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle)); } -FileRef::FileRef(File *file) +FileRef::FileRef(File *file) : + d(new FileRefPrivate(file)) { - d = new FileRefPrivate(file); } -FileRef::FileRef(const FileRef &ref) : d(ref.d) +FileRef::FileRef(const FileRef &ref) : + d(ref.d) { d->ref(); } @@ -133,7 +268,7 @@ const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static { - FileRefPrivate::fileTypeResolvers.prepend(resolver); + fileTypeResolvers.prepend(resolver); return resolver; } @@ -155,6 +290,7 @@ l.append("m4p"); l.append("3g2"); l.append("mp4"); + l.append("m4v"); l.append("wma"); l.append("asf"); l.append("aif"); @@ -174,113 +310,34 @@ bool FileRef::isNull() const { - return !d->file || !d->file->isValid(); + return (!d->file || !d->file->isValid()); } FileRef &FileRef::operator=(const FileRef &ref) { - if(&ref == this) - return *this; - - if(d->deref()) - delete d; + FileRef(ref).swap(*this); + return *this; +} - d = ref.d; - d->ref(); +void FileRef::swap(FileRef &ref) +{ + using std::swap; - return *this; + swap(d, ref.d); } bool FileRef::operator==(const FileRef &ref) const { - return ref.d->file == d->file; + return (ref.d->file == d->file); } bool FileRef::operator!=(const FileRef &ref) const { - return ref.d->file != d->file; + return (ref.d->file != d->file); } File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) // static { - - List::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin(); - - for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) { - File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); - if(file) - return file; - } - - // Ok, this is really dumb for now, but it works for testing. - - String ext; - { -#ifdef _WIN32 - - String s = fileName.toString(); - -#else - - String s = fileName; - - #endif - - const int pos = s.rfind("."); - if(pos != -1) - ext = s.substr(pos + 1).upper(); - } - - // If this list is updated, the method defaultFileExtensions() should also be - // updated. However at some point that list should be created at the same time - // that a default file type resolver is created. - - if(!ext.isEmpty()) { - if(ext == "MP3") - return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OGG") - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OGA") { - /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ - File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if (file->isValid()) - return file; - delete file; - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - } - if(ext == "FLAC") - return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "MPC") - return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WV") - return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "SPX") - return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OPUS") - return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "TTA") - return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") - return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WMA" || ext == "ASF") - return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") - return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WAV") - return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "APE") - return new APE::File(fileName, readAudioProperties, audioPropertiesStyle); - // module, nst and wow are possible but uncommon extensions - if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") - return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "S3M") - return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "IT") - return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "XM") - return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); - } - - return 0; + return createInternal(fileName, readAudioProperties, audioPropertiesStyle); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/fileref.h clementine-1.3.1-218/3rdparty/taglib/fileref.h --- clementine-1.3.1-217/3rdparty/taglib/fileref.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/fileref.h 2016-07-19 15:25:23.000000000 +0000 @@ -128,6 +128,23 @@ audioPropertiesStyle = AudioProperties::Average); /*! + * Construct a FileRef from an opened \a IOStream. If \a readAudioProperties + * is true then the audio properties will be read using \a audioPropertiesStyle. + * If \a readAudioProperties is false then \a audioPropertiesStyle will be + * ignored. + * + * Also see the note in the class documentation about why you may not want to + * use this method in your application. + * + * \note TagLib will *not* take ownership of the stream, the caller is + * responsible for deleting it after the File object. + */ + explicit FileRef(IOStream* stream, + bool readAudioProperties = true, + AudioProperties::ReadStyle + audioPropertiesStyle = AudioProperties::Average); + + /*! * Construct a FileRef using \a file. The FileRef now takes ownership of the * pointer and will delete the File when it passes out of scope. */ @@ -227,6 +244,11 @@ FileRef &operator=(const FileRef &ref); /*! + * Exchanges the content of the FileRef by the content of \a ref. + */ + void swap(FileRef &ref); + + /*! * Returns true if this FileRef and \a ref point to the same File object. */ bool operator==(const FileRef &ref) const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/flac/flacfile.cpp clementine-1.3.1-218/3rdparty/taglib/flac/flacfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/flac/flacfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/flac/flacfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -44,41 +45,42 @@ namespace { + typedef List BlockList; + typedef BlockList::Iterator BlockIterator; + typedef BlockList::Iterator BlockConstIterator; + enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 }; - enum { MinPaddingLength = 4096 }; - enum { LastBlockFlag = 0x80 }; + + const long MinPaddingLength = 4096; + const long MaxPaddingLegnth = 1024 * 1024; + + const char LastBlockFlag = '\x80'; } class FLAC::File::FilePrivate { public: - FilePrivate() : - ID3v2FrameFactory(ID3v2::FrameFactory::instance()), + FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : + ID3v2FrameFactory(frameFactory), ID3v2Location(-1), ID3v2OriginalSize(0), ID3v1Location(-1), properties(0), flacStart(0), streamStart(0), - scanned(false), - hasXiphComment(false), - hasID3v2(false), - hasID3v1(false) + scanned(false) { + blocks.setAutoDelete(true); } ~FilePrivate() { - uint size = blocks.size(); - for(uint i = 0; i < size; i++) { - delete blocks[i]; - } delete properties; } const ID3v2::FrameFactory *ID3v2FrameFactory; long ID3v2Location; - uint ID3v2OriginalSize; + long ID3v2OriginalSize; long ID3v1Location; @@ -86,15 +88,11 @@ Properties *properties; ByteVector xiphCommentData; - List blocks; + BlockList blocks; long flacStart; long streamStart; bool scanned; - - bool hasXiphComment; - bool hasID3v2; - bool hasID3v1; }; //////////////////////////////////////////////////////////////////////////////// @@ -112,9 +110,8 @@ FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle) : TagLib::File(file), - d(new FilePrivate()) + d(new FilePrivate(frameFactory)) { - d->ID3v2FrameFactory = frameFactory; if(isOpen()) read(readProperties); } @@ -122,9 +119,8 @@ FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle) : TagLib::File(stream), - d(new FilePrivate()) + d(new FilePrivate(frameFactory)) { - d->ID3v2FrameFactory = frameFactory; if(isOpen()) read(readProperties); } @@ -141,30 +137,17 @@ PropertyMap FLAC::File::properties() const { - // once Tag::properties() is virtual, this case distinction could actually be done - // within TagUnion. - if(d->hasXiphComment) - return d->tag.access(FlacXiphIndex, false)->properties(); - if(d->hasID3v2) - return d->tag.access(FlacID3v2Index, false)->properties(); - if(d->hasID3v1) - return d->tag.access(FlacID3v1Index, false)->properties(); - return PropertyMap(); + return d->tag.properties(); } void FLAC::File::removeUnsupportedProperties(const StringList &unsupported) { - if(d->hasXiphComment) - d->tag.access(FlacXiphIndex, false)->removeUnsupportedProperties(unsupported); - if(d->hasID3v2) - d->tag.access(FlacID3v2Index, false)->removeUnsupportedProperties(unsupported); - if(d->hasID3v1) - d->tag.access(FlacID3v1Index, false)->removeUnsupportedProperties(unsupported); + d->tag.removeUnsupportedProperties(unsupported); } PropertyMap FLAC::File::setProperties(const PropertyMap &properties) { - return d->tag.access(FlacXiphIndex, true)->setProperties(properties); + return xiphComment(true)->setProperties(properties); } FLAC::Properties *FLAC::File::audioProperties() const @@ -192,73 +175,105 @@ // Replace metadata blocks - bool foundVorbisCommentBlock = false; - List newBlocks; - for(uint i = 0; i < d->blocks.size(); i++) { - MetadataBlock *block = d->blocks[i]; - if(block->code() == MetadataBlock::VorbisComment) { + for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { + if((*it)->code() == MetadataBlock::VorbisComment) { // Set the new Vorbis Comment block - delete block; - block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData); - foundVorbisCommentBlock = true; - } - if(block->code() == MetadataBlock::Padding) { - delete block; - continue; + delete *it; + d->blocks.erase(it); + break; } - newBlocks.append(block); - } - if(!foundVorbisCommentBlock) { - newBlocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)); - foundVorbisCommentBlock = true; } - d->blocks = newBlocks; + + d->blocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)); // Render data for the metadata blocks ByteVector data; - for(uint i = 0; i < newBlocks.size(); i++) { - FLAC::MetadataBlock *block = newBlocks[i]; - ByteVector blockData = block->render(); + for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { + ByteVector blockData = (*it)->render(); ByteVector blockHeader = ByteVector::fromUInt(blockData.size()); - blockHeader[0] = block->code(); + blockHeader[0] = (*it)->code(); data.append(blockHeader); data.append(blockData); } - // Adjust the padding block(s) + // Compute the amount of padding, and append that to data. + // TODO: Should be calculated in offset_t in taglib2. long originalLength = d->streamStart - d->flacStart; - int paddingLength = originalLength - data.size() - 4; + long paddingLength = originalLength - data.size() - 4; + if(paddingLength <= 0) { paddingLength = MinPaddingLength; } - ByteVector padding = ByteVector::fromUInt(paddingLength); - padding.resize(paddingLength + 4); - padding[0] = (char)(FLAC::MetadataBlock::Padding | LastBlockFlag); - data.append(padding); + else { + // Padding won't increase beyond 1% of the file size or 1MB. + + long threshold = length() / 100; + threshold = std::max(threshold, MinPaddingLength); + threshold = std::min(threshold, MaxPaddingLegnth); + + if(paddingLength > threshold) + paddingLength = MinPaddingLength; + } + + ByteVector paddingHeader = ByteVector::fromUInt(paddingLength); + paddingHeader[0] = static_cast(MetadataBlock::Padding | LastBlockFlag); + data.append(paddingHeader); + data.resize(static_cast(data.size() + paddingLength)); // Write the data to the file insert(data, d->flacStart, originalLength); - d->hasXiphComment = true; + + d->streamStart += (static_cast(data.size()) - originalLength); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - originalLength); // Update ID3 tags - if(ID3v2Tag()) { - if(d->hasID3v2) { - if(d->ID3v2Location < d->flacStart) - debug("FLAC::File::save() -- This can't be right -- an ID3v2 tag after the " - "start of the FLAC bytestream? Not writing the ID3v2 tag."); - else - insert(ID3v2Tag()->render(), d->ID3v2Location, d->ID3v2OriginalSize); + if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { + + // ID3v2 tag is not empty. Update the old one or create a new one. + + if(d->ID3v2Location < 0) + d->ID3v2Location = 0; + + data = ID3v2Tag()->render(); + insert(data, d->ID3v2Location, d->ID3v2OriginalSize); + + d->flacStart += (static_cast(data.size()) - d->ID3v2OriginalSize); + d->streamStart += (static_cast(data.size()) - d->ID3v2OriginalSize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->ID3v2OriginalSize); + + d->ID3v2OriginalSize = data.size(); + } + else { + + // ID3v2 tag is empty. Remove the old one. + + if(d->ID3v2Location >= 0) { + removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); + + d->flacStart -= d->ID3v2OriginalSize; + d->streamStart -= d->ID3v2OriginalSize; + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->ID3v2OriginalSize; + + d->ID3v2Location = -1; + d->ID3v2OriginalSize = 0; } - else - insert(ID3v2Tag()->render(), 0, 0); } - if(ID3v1Tag()) { - if(d->hasID3v1) { + if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { + + // ID3v1 tag is not empty. Update the old one or create a new one. + + if(d->ID3v1Location >= 0) { seek(d->ID3v1Location); } else { @@ -267,7 +282,15 @@ } writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; + } + else { + + // ID3v1 tag is empty. Remove the old one. + + if(d->ID3v1Location >= 0) { + truncate(d->ID3v1Location); + d->ID3v1Location = -1; + } } return true; @@ -312,8 +335,8 @@ List FLAC::File::pictureList() { List pictures; - for(uint i = 0; i < d->blocks.size(); i++) { - Picture *picture = dynamic_cast(d->blocks[i]); + for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { + Picture *picture = dynamic_cast(*it); if(picture) { pictures.append(picture); } @@ -328,8 +351,7 @@ void FLAC::File::removePicture(Picture *picture, bool del) { - MetadataBlock *block = picture; - List::Iterator it = d->blocks.find(block); + BlockIterator it = d->blocks.find(picture); if(it != d->blocks.end()) d->blocks.erase(it); @@ -339,32 +361,44 @@ void FLAC::File::removePictures() { - List newBlocks; - for(uint i = 0; i < d->blocks.size(); i++) { - Picture *picture = dynamic_cast(d->blocks[i]); - if(picture) { - delete picture; + for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ) { + if(dynamic_cast(*it)) { + delete *it; + it = d->blocks.erase(it); } else { - newBlocks.append(d->blocks[i]); + ++it; } } - d->blocks = newBlocks; +} + +void FLAC::File::strip(int tags) +{ + if(tags & ID3v1) + d->tag.set(FlacID3v1Index, 0); + + if(tags & ID3v2) + d->tag.set(FlacID3v2Index, 0); + + if(tags & XiphComment) { + xiphComment()->removeAllFields(); + xiphComment()->removeAllPictures(); + } } bool FLAC::File::hasXiphComment() const { - return d->hasXiphComment; + return !d->xiphCommentData.isEmpty(); } bool FLAC::File::hasID3v1Tag() const { - return d->hasID3v1; + return (d->ID3v1Location >= 0); } bool FLAC::File::hasID3v2Tag() const { - return d->hasID3v2; + return (d->ID3v2Location >= 0); } //////////////////////////////////////////////////////////////////////////////// @@ -375,28 +409,19 @@ { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { - d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); - d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); - - if(ID3v2Tag()->header()->tagSize() <= 0) - d->tag.set(FlacID3v2Index, 0); - else - d->hasID3v2 = true; } // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); - if(d->ID3v1Location >= 0) { + if(d->ID3v1Location >= 0) d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } // Look for FLAC metadata, including vorbis comments @@ -405,10 +430,10 @@ if(!isValid()) return; - if(d->hasXiphComment) + if(!d->xiphCommentData.isEmpty()) d->tag.set(FlacXiphIndex, new Ogg::XiphComment(d->xiphCommentData)); else - d->tag.set(FlacXiphIndex, new Ogg::XiphComment); + d->tag.set(FlacXiphIndex, new Ogg::XiphComment()); if(readProperties) { @@ -418,10 +443,10 @@ long streamLength; - if(d->hasID3v1) + if(d->ID3v1Location >= 0) streamLength = d->ID3v1Location - d->streamStart; else - streamLength = File::length() - d->streamStart; + streamLength = length() - d->streamStart; d->properties = new Properties(infoData, streamLength); } @@ -439,7 +464,7 @@ long nextBlockOffset; - if(d->hasID3v2) + if(d->ID3v2Location >= 0) nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize); else nextBlockOffset = find("fLaC"); @@ -453,51 +478,43 @@ nextBlockOffset += 4; d->flacStart = nextBlockOffset; - seek(nextBlockOffset); + while(true) { - ByteVector header = readBlock(4); - - // Header format (from spec): - // <1> Last-metadata-block flag - // <7> BLOCK_TYPE - // 0 : STREAMINFO - // 1 : PADDING - // .. - // 4 : VORBIS_COMMENT - // .. - // <24> Length of metadata to follow - - char blockType = header[0] & 0x7f; - bool isLastBlock = (header[0] & 0x80) != 0; - uint length = header.toUInt(1U, 3U); - - // First block should be the stream_info metadata - - if(blockType != MetadataBlock::StreamInfo) { - debug("FLAC::File::scan() -- invalid FLAC stream"); - setValid(false); - return; - } + seek(nextBlockOffset); + const ByteVector header = readBlock(4); - d->blocks.append(new UnknownMetadataBlock(blockType, readBlock(length))); - nextBlockOffset += length + 4; + // Header format (from spec): + // <1> Last-metadata-block flag + // <7> BLOCK_TYPE + // 0 : STREAMINFO + // 1 : PADDING + // .. + // 4 : VORBIS_COMMENT + // .. + // 6 : PICTURE + // .. + // <24> Length of metadata to follow + + const char blockType = header[0] & ~LastBlockFlag; + const bool isLastBlock = (header[0] & LastBlockFlag) != 0; + const unsigned int blockLength = header.toUInt(1U, 3U); - // Search through the remaining metadata - while(!isLastBlock) { + // First block should be the stream_info metadata - header = readBlock(4); - blockType = header[0] & 0x7f; - isLastBlock = (header[0] & 0x80) != 0; - length = header.toUInt(1U, 3U); + if(d->blocks.isEmpty() && blockType != MetadataBlock::StreamInfo) { + debug("FLAC::File::scan() -- First block should be the stream_info metadata"); + setValid(false); + return; + } - if(length == 0 && blockType != MetadataBlock::Padding) { + if(blockLength == 0 && blockType != MetadataBlock::Padding) { debug("FLAC::File::scan() -- Zero-sized metadata block found"); setValid(false); return; } - const ByteVector data = readBlock(length); - if(data.size() != length) { + const ByteVector data = readBlock(blockLength); + if(data.size() != blockLength) { debug("FLAC::File::scan() -- Failed to read a metadata block"); setValid(false); return; @@ -507,12 +524,12 @@ // Found the vorbis-comment if(blockType == MetadataBlock::VorbisComment) { - if(!d->hasXiphComment) { + if(d->xiphCommentData.isEmpty()) { d->xiphCommentData = data; - d->hasXiphComment = true; + block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, data); } else { - debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one"); + debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, discarding"); } } else if(blockType == MetadataBlock::Picture) { @@ -525,25 +542,20 @@ delete picture; } } - - if(!block) { - block = new UnknownMetadataBlock(blockType, data); - } - if(block->code() != MetadataBlock::Padding) { - d->blocks.append(block); + else if(blockType == MetadataBlock::Padding) { + // Skip all padding blocks. } else { - delete block; + block = new UnknownMetadataBlock(blockType, data); } - nextBlockOffset += length + 4; + if(block) + d->blocks.append(block); - if(nextBlockOffset >= File::length()) { - debug("FLAC::File::scan() -- FLAC stream corrupted"); - setValid(false); - return; - } - seek(nextBlockOffset); + nextBlockOffset += blockLength + 4; + + if(isLastBlock) + break; } // End of metadata, now comes the datastream @@ -552,30 +564,3 @@ d->scanned = true; } - -long FLAC::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long FLAC::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff -Nru clementine-1.3.1-217/3rdparty/taglib/flac/flacfile.h clementine-1.3.1-218/3rdparty/taglib/flac/flacfile.h --- clementine-1.3.1-217/3rdparty/taglib/flac/flacfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/flac/flacfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -67,6 +67,23 @@ { public: /*! + * This set of flags is used for various operations and is suitable for + * being OR-ed together. + */ + enum TagTypes { + //! Empty set. Matches no tag types. + NoTags = 0x0000, + //! Matches Vorbis comments. + XiphComment = 0x0001, + //! Matches ID3v1 tags. + ID3v1 = 0x0002, + //! Matches ID3v2 tags. + ID3v2 = 0x0004, + //! Matches all tag types. + AllTags = 0xffff + }; + + /*! * Constructs a FLAC file from \a file. If \a readProperties is true the * file's audio properties will also be read. * @@ -155,9 +172,6 @@ * has no XiphComment, one will be constructed from the ID3-tags. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ virtual bool save(); @@ -269,6 +283,21 @@ void addPicture(Picture *picture); /*! + * This will remove the tags that match the OR-ed together TagTypes from + * the file. By default it removes all tags. + * + * \warning This will also invalidate pointers to the tags as their memory + * will be freed. + * + * \note In order to make the removal permanent save() still needs to be + * called. + * + * \note This won't remove the Vorbis comment block completely. The + * vendor ID will be preserved. + */ + void strip(int tags = AllTags); + + /*! * Returns whether or not the file on disk actually has a XiphComment. * * \see xiphComment() @@ -295,8 +324,6 @@ void read(bool readProperties); void scan(); - long findID3v2(); - long findID3v1(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/flac/flacpicture.cpp clementine-1.3.1-218/3rdparty/taglib/flac/flacpicture.cpp --- clementine-1.3.1-217/3rdparty/taglib/flac/flacpicture.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/flac/flacpicture.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -78,10 +78,10 @@ return false; } - uint pos = 0; + unsigned int pos = 0; d->type = FLAC::Picture::Type(data.toUInt(pos)); pos += 4; - uint mimeTypeLength = data.toUInt(pos); + unsigned int mimeTypeLength = data.toUInt(pos); pos += 4; if(pos + mimeTypeLength + 24 > data.size()) { debug("Invalid picture block."); @@ -89,7 +89,7 @@ } d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8); pos += mimeTypeLength; - uint descriptionLength = data.toUInt(pos); + unsigned int descriptionLength = data.toUInt(pos); pos += 4; if(pos + descriptionLength + 20 > data.size()) { debug("Invalid picture block."); @@ -105,7 +105,7 @@ pos += 4; d->numColors = data.toUInt(pos); pos += 4; - uint dataLength = data.toUInt(pos); + unsigned int dataLength = data.toUInt(pos); pos += 4; if(pos + dataLength > data.size()) { debug("Invalid picture block."); diff -Nru clementine-1.3.1-217/3rdparty/taglib/flac/flacproperties.cpp clementine-1.3.1-218/3rdparty/taglib/flac/flacproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/flac/flacproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/flac/flacproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -135,7 +135,7 @@ return; } - uint pos = 0; + unsigned int pos = 0; // Minimum block size (in samples) pos += 2; @@ -149,7 +149,7 @@ // Maximum frame size (in bytes) pos += 3; - const uint flags = data.toUInt(pos, true); + const unsigned int flags = data.toUInt(pos, true); pos += 4; d->sampleRate = flags >> 12; @@ -159,8 +159,8 @@ // The last 4 bits are the most significant 4 bits for the 36 bit // stream length in samples. (Audio files measured in days) - const ulonglong hi = flags & 0xf; - const ulonglong lo = data.toUInt(pos, true); + const unsigned long long hi = flags & 0xf; + const unsigned long long lo = data.toUInt(pos, true); pos += 4; d->sampleFrames = (hi << 32) | lo; diff -Nru clementine-1.3.1-217/3rdparty/taglib/it/itfile.cpp clementine-1.3.1-218/3rdparty/taglib/it/itfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/it/itfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/it/itfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "tstringlist.h" #include "itfile.h" #include "tdebug.h" @@ -96,9 +101,9 @@ seek(2, Current); - ushort length = 0; - ushort instrumentCount = 0; - ushort sampleCount = 0; + unsigned short length = 0; + unsigned short instrumentCount = 0; + unsigned short sampleCount = 0; if(!readU16L(length) || !readU16L(instrumentCount) || !readU16L(sampleCount)) return false; @@ -107,9 +112,9 @@ // write comment as instrument and sample names: StringList lines = d->tag.comment().split("\n"); - for(ushort i = 0; i < instrumentCount; ++ i) { + for(unsigned short i = 0; i < instrumentCount; ++ i) { seek(192L + length + ((long)i << 2)); - ulong instrumentOffset = 0; + unsigned long instrumentOffset = 0; if(!readU32L(instrumentOffset)) return false; @@ -118,28 +123,28 @@ if(i < lines.size()) writeString(lines[i], 25); else - writeString(String::null, 25); + writeString(String(), 25); writeByte(0); } - for(ushort i = 0; i < sampleCount; ++ i) { + for(unsigned short i = 0; i < sampleCount; ++ i) { seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2)); - ulong sampleOffset = 0; + unsigned long sampleOffset = 0; if(!readU32L(sampleOffset)) return false; seek(sampleOffset + 20); - if((TagLib::uint)(i + instrumentCount) < lines.size()) + if((unsigned int)(i + instrumentCount) < lines.size()) writeString(lines[i + instrumentCount], 25); else - writeString(String::null, 25); + writeString(String(), 25); writeByte(0); } // write rest as message: StringList messageLines; - for(uint i = instrumentCount + sampleCount; i < lines.size(); ++ i) + for(unsigned int i = instrumentCount + sampleCount; i < lines.size(); ++ i) messageLines.append(lines[i]); ByteVector message = messageLines.toString("\r").data(String::Latin1); @@ -149,15 +154,15 @@ message.resize(7999); message.append((char)0); - ushort special = 0; - ushort messageLength = 0; - ulong messageOffset = 0; + unsigned short special = 0; + unsigned short messageLength = 0; + unsigned long messageOffset = 0; seek(46); if(!readU16L(special)) return false; - ulong fileSize = File::length(); + unsigned long fileSize = File::length(); if(special & Properties::MessageAttached) { seek(54); if(!readU16L(messageLength) || !readU32L(messageOffset)) @@ -259,8 +264,8 @@ d->properties.setChannels(channels); // real length might be shorter because of skips and terminator - ushort realLength = 0; - for(ushort i = 0; i < length; ++ i) { + unsigned short realLength = 0; + for(unsigned short i = 0; i < length; ++ i) { READ_BYTE_AS(order); if(order == 255) break; if(order != 254) ++ realLength; @@ -274,7 +279,7 @@ // Currently I just discard anything after a nil, but // e.g. VLC seems to interprete a nil as a space. I // don't know what is the proper behaviour. - for(ushort i = 0; i < instrumentCount; ++ i) { + for(unsigned short i = 0; i < instrumentCount; ++ i) { seek(192L + length + ((long)i << 2)); READ_U32L_AS(instrumentOffset); seek(instrumentOffset); @@ -290,7 +295,7 @@ comment.append(instrumentName); } - for(ushort i = 0; i < sampleCount; ++ i) { + for(unsigned short i = 0; i < sampleCount; ++ i) { seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2)); READ_U32L_AS(sampleOffset); diff -Nru clementine-1.3.1-217/3rdparty/taglib/it/itproperties.cpp clementine-1.3.1-218/3rdparty/taglib/it/itproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/it/itproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/it/itproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "itproperties.h" using namespace TagLib; @@ -46,21 +51,21 @@ { } - int channels; - ushort lengthInPatterns; - ushort instrumentCount; - ushort sampleCount; - ushort patternCount; - ushort version; - ushort compatibleVersion; - ushort flags; - ushort special; - uchar globalVolume; - uchar mixVolume; - uchar tempo; - uchar bpmSpeed; - uchar panningSeparation; - uchar pitchWheelDepth; + int channels; + unsigned short lengthInPatterns; + unsigned short instrumentCount; + unsigned short sampleCount; + unsigned short patternCount; + unsigned short version; + unsigned short compatibleVersion; + unsigned short flags; + unsigned short special; + unsigned char globalVolume; + unsigned char mixVolume; + unsigned char tempo; + unsigned char bpmSpeed; + unsigned char panningSeparation; + unsigned char pitchWheelDepth; }; IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : @@ -104,7 +109,7 @@ return d->channels; } -TagLib::ushort IT::Properties::lengthInPatterns() const +unsigned short IT::Properties::lengthInPatterns() const { return d->lengthInPatterns; } @@ -114,67 +119,67 @@ return d->flags & Stereo; } -TagLib::ushort IT::Properties::instrumentCount() const +unsigned short IT::Properties::instrumentCount() const { return d->instrumentCount; } -TagLib::ushort IT::Properties::sampleCount() const +unsigned short IT::Properties::sampleCount() const { return d->sampleCount; } -TagLib::ushort IT::Properties::patternCount() const +unsigned short IT::Properties::patternCount() const { return d->patternCount; } -TagLib::ushort IT::Properties::version() const +unsigned short IT::Properties::version() const { return d->version; } -TagLib::ushort IT::Properties::compatibleVersion() const +unsigned short IT::Properties::compatibleVersion() const { return d->compatibleVersion; } -TagLib::ushort IT::Properties::flags() const +unsigned short IT::Properties::flags() const { return d->flags; } -TagLib::ushort IT::Properties::special() const +unsigned short IT::Properties::special() const { return d->special; } -uchar IT::Properties::globalVolume() const +unsigned char IT::Properties::globalVolume() const { return d->globalVolume; } -uchar IT::Properties::mixVolume() const +unsigned char IT::Properties::mixVolume() const { return d->mixVolume; } -uchar IT::Properties::tempo() const +unsigned char IT::Properties::tempo() const { return d->tempo; } -uchar IT::Properties::bpmSpeed() const +unsigned char IT::Properties::bpmSpeed() const { return d->bpmSpeed; } -uchar IT::Properties::panningSeparation() const +unsigned char IT::Properties::panningSeparation() const { return d->panningSeparation; } -uchar IT::Properties::pitchWheelDepth() const +unsigned char IT::Properties::pitchWheelDepth() const { return d->pitchWheelDepth; } @@ -184,72 +189,72 @@ d->channels = channels; } -void IT::Properties::setLengthInPatterns(ushort lengthInPatterns) +void IT::Properties::setLengthInPatterns(unsigned short lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } -void IT::Properties::setInstrumentCount(ushort instrumentCount) +void IT::Properties::setInstrumentCount(unsigned short instrumentCount) { d->instrumentCount = instrumentCount; } -void IT::Properties::setSampleCount(ushort sampleCount) +void IT::Properties::setSampleCount(unsigned short sampleCount) { d->sampleCount = sampleCount; } -void IT::Properties::setPatternCount(ushort patternCount) +void IT::Properties::setPatternCount(unsigned short patternCount) { d->patternCount = patternCount; } -void IT::Properties::setFlags(ushort flags) +void IT::Properties::setFlags(unsigned short flags) { d->flags = flags; } -void IT::Properties::setSpecial(ushort special) +void IT::Properties::setSpecial(unsigned short special) { d->special = special; } -void IT::Properties::setCompatibleVersion(ushort compatibleVersion) +void IT::Properties::setCompatibleVersion(unsigned short compatibleVersion) { d->compatibleVersion = compatibleVersion; } -void IT::Properties::setVersion(ushort version) +void IT::Properties::setVersion(unsigned short version) { d->version = version; } -void IT::Properties::setGlobalVolume(uchar globalVolume) +void IT::Properties::setGlobalVolume(unsigned char globalVolume) { d->globalVolume = globalVolume; } -void IT::Properties::setMixVolume(uchar mixVolume) +void IT::Properties::setMixVolume(unsigned char mixVolume) { d->mixVolume = mixVolume; } -void IT::Properties::setTempo(uchar tempo) +void IT::Properties::setTempo(unsigned char tempo) { d->tempo = tempo; } -void IT::Properties::setBpmSpeed(uchar bpmSpeed) +void IT::Properties::setBpmSpeed(unsigned char bpmSpeed) { d->bpmSpeed = bpmSpeed; } -void IT::Properties::setPanningSeparation(uchar panningSeparation) +void IT::Properties::setPanningSeparation(unsigned char panningSeparation) { d->panningSeparation = panningSeparation; } -void IT::Properties::setPitchWheelDepth(uchar pitchWheelDepth) +void IT::Properties::setPitchWheelDepth(unsigned char pitchWheelDepth) { d->pitchWheelDepth = pitchWheelDepth; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/it/itproperties.h clementine-1.3.1-218/3rdparty/taglib/it/itproperties.h --- clementine-1.3.1-217/3rdparty/taglib/it/itproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/it/itproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ITPROPERTIES_H @@ -58,37 +62,37 @@ int sampleRate() const; int channels() const; - ushort lengthInPatterns() const; - bool stereo() const; - ushort instrumentCount() const; - ushort sampleCount() const; - ushort patternCount() const; - ushort version() const; - ushort compatibleVersion() const; - ushort flags() const; - ushort special() const; - uchar globalVolume() const; - uchar mixVolume() const; - uchar tempo() const; - uchar bpmSpeed() const; - uchar panningSeparation() const; - uchar pitchWheelDepth() const; + unsigned short lengthInPatterns() const; + bool stereo() const; + unsigned short instrumentCount() const; + unsigned short sampleCount() const; + unsigned short patternCount() const; + unsigned short version() const; + unsigned short compatibleVersion() const; + unsigned short flags() const; + unsigned short special() const; + unsigned char globalVolume() const; + unsigned char mixVolume() const; + unsigned char tempo() const; + unsigned char bpmSpeed() const; + unsigned char panningSeparation() const; + unsigned char pitchWheelDepth() const; void setChannels(int channels); - void setLengthInPatterns(ushort lengthInPatterns); - void setInstrumentCount(ushort instrumentCount); - void setSampleCount (ushort sampleCount); - void setPatternCount(ushort patternCount); - void setVersion (ushort version); - void setCompatibleVersion(ushort compatibleVersion); - void setFlags (ushort flags); - void setSpecial (ushort special); - void setGlobalVolume(uchar globalVolume); - void setMixVolume (uchar mixVolume); - void setTempo (uchar tempo); - void setBpmSpeed (uchar bpmSpeed); - void setPanningSeparation(uchar panningSeparation); - void setPitchWheelDepth (uchar pitchWheelDepth); + void setLengthInPatterns(unsigned short lengthInPatterns); + void setInstrumentCount(unsigned short instrumentCount); + void setSampleCount (unsigned short sampleCount); + void setPatternCount(unsigned short patternCount); + void setVersion (unsigned short version); + void setCompatibleVersion(unsigned short compatibleVersion); + void setFlags (unsigned short flags); + void setSpecial (unsigned short special); + void setGlobalVolume(unsigned char globalVolume); + void setMixVolume (unsigned char mixVolume); + void setTempo (unsigned char tempo); + void setBpmSpeed (unsigned char bpmSpeed); + void setPanningSeparation(unsigned char panningSeparation); + void setPitchWheelDepth (unsigned char pitchWheelDepth); private: Properties(const Properties&); diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modfilebase.cpp clementine-1.3.1-218/3rdparty/taglib/mod/modfilebase.cpp --- clementine-1.3.1-217/3rdparty/taglib/mod/modfilebase.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modfilebase.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "tdebug.h" #include "modfilebase.h" @@ -33,14 +38,14 @@ { } -void Mod::FileBase::writeString(const String &s, ulong size, char padding) +void Mod::FileBase::writeString(const String &s, unsigned long size, char padding) { ByteVector data(s.data(String::Latin1)); data.resize(size, padding); writeBlock(data); } -bool Mod::FileBase::readString(String &s, ulong size) +bool Mod::FileBase::readString(String &s, unsigned long size) { ByteVector data(readBlock(size)); if(data.size() < size) return false; @@ -49,39 +54,39 @@ { data.resize(index); } - data.replace((char) 0xff, ' '); + data.replace('\xff', ' '); s = data; return true; } -void Mod::FileBase::writeByte(uchar byte) +void Mod::FileBase::writeByte(unsigned char byte) { ByteVector data(1, byte); writeBlock(data); } -void Mod::FileBase::writeU16L(ushort number) +void Mod::FileBase::writeU16L(unsigned short number) { writeBlock(ByteVector::fromShort(number, false)); } -void Mod::FileBase::writeU32L(ulong number) +void Mod::FileBase::writeU32L(unsigned long number) { writeBlock(ByteVector::fromUInt(number, false)); } -void Mod::FileBase::writeU16B(ushort number) +void Mod::FileBase::writeU16B(unsigned short number) { writeBlock(ByteVector::fromShort(number, true)); } -void Mod::FileBase::writeU32B(ulong number) +void Mod::FileBase::writeU32B(unsigned long number) { writeBlock(ByteVector::fromUInt(number, true)); } -bool Mod::FileBase::readByte(uchar &byte) +bool Mod::FileBase::readByte(unsigned char &byte) { ByteVector data(readBlock(1)); if(data.size() < 1) return false; @@ -89,7 +94,7 @@ return true; } -bool Mod::FileBase::readU16L(ushort &number) +bool Mod::FileBase::readU16L(unsigned short &number) { ByteVector data(readBlock(2)); if(data.size() < 2) return false; @@ -97,14 +102,14 @@ return true; } -bool Mod::FileBase::readU32L(ulong &number) { +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(ushort &number) +bool Mod::FileBase::readU16B(unsigned short &number) { ByteVector data(readBlock(2)); if(data.size() < 2) return false; @@ -112,7 +117,7 @@ return true; } -bool Mod::FileBase::readU32B(ulong &number) { +bool Mod::FileBase::readU32B(unsigned long &number) { ByteVector data(readBlock(4)); if(data.size() < 4) return false; number = data.toUInt(true); diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modfilebase.h clementine-1.3.1-218/3rdparty/taglib/mod/modfilebase.h --- clementine-1.3.1-217/3rdparty/taglib/mod/modfilebase.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modfilebase.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MODFILEBASE_H @@ -40,19 +44,19 @@ FileBase(FileName file); FileBase(IOStream *stream); - void writeString(const String &s, ulong size, char padding = 0); - void writeByte(uchar byte); - void writeU16L(ushort number); - void writeU32L(ulong number); - void writeU16B(ushort number); - void writeU32B(ulong number); - - bool readString(String &s, ulong size); - bool readByte(uchar &byte); - bool readU16L(ushort &number); - bool readU32L(ulong &number); - bool readU16B(ushort &number); - bool readU32B(ulong &number); + void writeString(const String &s, unsigned long size, char padding = 0); + void writeByte(unsigned char byte); + void writeU16L(unsigned short number); + void writeU32L(unsigned long number); + void writeU16B(unsigned short number); + void writeU32B(unsigned long number); + + bool readString(String &s, unsigned long size); + bool readByte(unsigned char &byte); + bool readU16L(unsigned short &number); + bool readU32L(unsigned long &number); + bool readU16B(unsigned short &number); + bool readU32B(unsigned long &number); }; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modfile.cpp clementine-1.3.1-218/3rdparty/taglib/mod/modfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/mod/modfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "modfile.h" #include "tstringlist.h" #include "tdebug.h" @@ -92,14 +97,14 @@ seek(0); writeString(d->tag.title(), 20); StringList lines = d->tag.comment().split("\n"); - uint n = std::min(lines.size(), d->properties.instrumentCount()); - for(uint i = 0; i < n; ++ i) { + unsigned int n = std::min(lines.size(), d->properties.instrumentCount()); + for(unsigned int i = 0; i < n; ++ i) { writeString(lines[i], 22); seek(8, Current); } - for(uint i = n; i < d->properties.instrumentCount(); ++ i) { - writeString(String::null, 22); + for(unsigned int i = n; i < d->properties.instrumentCount(); ++ i) { + writeString(String(), 22); seek(8, Current); } return true; @@ -114,8 +119,8 @@ ByteVector modId = readBlock(4); READ_ASSERT(modId.size() == 4); - int channels = 4; - uint instruments = 31; + int channels = 4; + unsigned int instruments = 31; if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.") { d->tag.setTrackerName("ProTracker"); channels = 4; @@ -159,7 +164,7 @@ READ_STRING(d->tag.setTitle, 20); StringList comment; - for(uint i = 0; i < instruments; ++ i) { + for(unsigned int i = 0; i < instruments; ++ i) { READ_STRING_AS(instrumentName, 22); // value in words, * 2 (<< 1) for bytes: READ_U16B_AS(sampleLength); diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modfile.h clementine-1.3.1-218/3rdparty/taglib/mod/modfile.h --- clementine-1.3.1-217/3rdparty/taglib/mod/modfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MODFILE_H diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modfileprivate.h clementine-1.3.1-218/3rdparty/taglib/mod/modfileprivate.h --- clementine-1.3.1-217/3rdparty/taglib/mod/modfileprivate.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modfileprivate.h 2016-07-19 15:25:23.000000000 +0000 @@ -37,11 +37,11 @@ setter(number); \ } -#define READ_BYTE(setter) READ(setter,uchar,readByte) -#define READ_U16L(setter) READ(setter,ushort,readU16L) -#define READ_U32L(setter) READ(setter,ulong,readU32L) -#define READ_U16B(setter) READ(setter,ushort,readU16B) -#define READ_U32B(setter) READ(setter,ulong,readU32B) +#define READ_BYTE(setter) READ(setter,unsigned char,readByte) +#define READ_U16L(setter) READ(setter,unsigned short,readU16L) +#define READ_U32L(setter) READ(setter,unsigned long,readU32L) +#define READ_U16B(setter) READ(setter,unsigned short,readU16B) +#define READ_U32B(setter) READ(setter,unsigned long,readU32B) #define READ_STRING(setter,size) \ { \ @@ -54,11 +54,11 @@ type name = 0; \ READ_ASSERT(read(name)); -#define READ_BYTE_AS(name) READ_AS(uchar,name,readByte) -#define READ_U16L_AS(name) READ_AS(ushort,name,readU16L) -#define READ_U32L_AS(name) READ_AS(ulong,name,readU32L) -#define READ_U16B_AS(name) READ_AS(ushort,name,readU16B) -#define READ_U32B_AS(name) READ_AS(ulong,name,readU32B) +#define READ_BYTE_AS(name) READ_AS(unsigned char,name,readByte) +#define READ_U16L_AS(name) READ_AS(unsigned short,name,readU16L) +#define READ_U32L_AS(name) READ_AS(unsigned long,name,readU32L) +#define READ_U16B_AS(name) READ_AS(unsigned short,name,readU16B) +#define READ_U32B_AS(name) READ_AS(unsigned long,name,readU32B) #define READ_STRING_AS(name,size) \ String name; \ diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modproperties.cpp clementine-1.3.1-218/3rdparty/taglib/mod/modproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/mod/modproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "modproperties.h" using namespace TagLib; @@ -34,9 +39,9 @@ { } - int channels; - uint instrumentCount; - uchar lengthInPatterns; + int channels; + unsigned int instrumentCount; + unsigned char lengthInPatterns; }; Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : @@ -80,12 +85,12 @@ return d->channels; } -TagLib::uint Mod::Properties::instrumentCount() const +unsigned int Mod::Properties::instrumentCount() const { return d->instrumentCount; } -uchar Mod::Properties::lengthInPatterns() const +unsigned char Mod::Properties::lengthInPatterns() const { return d->lengthInPatterns; } @@ -95,12 +100,12 @@ d->channels = channels; } -void Mod::Properties::setInstrumentCount(uint instrumentCount) +void Mod::Properties::setInstrumentCount(unsigned int instrumentCount) { d->instrumentCount = instrumentCount; } -void Mod::Properties::setLengthInPatterns(uchar lengthInPatterns) +void Mod::Properties::setLengthInPatterns(unsigned char lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modproperties.h clementine-1.3.1-218/3rdparty/taglib/mod/modproperties.h --- clementine-1.3.1-217/3rdparty/taglib/mod/modproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MODPROPERTIES_H @@ -42,13 +46,13 @@ int sampleRate() const; int channels() const; - uint instrumentCount() const; - uchar lengthInPatterns() const; + unsigned int instrumentCount() const; + unsigned char lengthInPatterns() const; void setChannels(int channels); - void setInstrumentCount(uint sampleCount); - void setLengthInPatterns(uchar lengthInPatterns); + void setInstrumentCount(unsigned int sampleCount); + void setLengthInPatterns(unsigned char lengthInPatterns); private: friend class File; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modtag.cpp clementine-1.3.1-218/3rdparty/taglib/mod/modtag.cpp --- clementine-1.3.1-217/3rdparty/taglib/mod/modtag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modtag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "modtag.h" #include "tstringlist.h" #include "tpropertymap.h" @@ -55,12 +60,12 @@ String Mod::Tag::artist() const { - return String::null; + return String(); } String Mod::Tag::album() const { - return String::null; + return String(); } String Mod::Tag::comment() const @@ -70,15 +75,15 @@ String Mod::Tag::genre() const { - return String::null; + return String(); } -TagLib::uint Mod::Tag::year() const +unsigned int Mod::Tag::year() const { return 0; } -TagLib::uint Mod::Tag::track() const +unsigned int Mod::Tag::track() const { return 0; } @@ -110,11 +115,11 @@ { } -void Mod::Tag::setYear(uint) +void Mod::Tag::setYear(unsigned int) { } -void Mod::Tag::setTrack(uint) +void Mod::Tag::setTrack(unsigned int) { } @@ -128,7 +133,7 @@ PropertyMap properties; properties["TITLE"] = d->title; properties["COMMENT"] = d->comment; - if(!(d->trackerName.isNull())) + if(!(d->trackerName.isEmpty())) properties["TRACKERNAME"] = d->trackerName; return properties; } @@ -142,19 +147,19 @@ d->title = properties["TITLE"].front(); oneValueSet.append("TITLE"); } else - d->title = String::null; + d->title.clear(); if(properties.contains("COMMENT")) { d->comment = properties["COMMENT"].front(); oneValueSet.append("COMMENT"); } else - d->comment = String::null; + d->comment.clear(); if(properties.contains("TRACKERNAME")) { d->trackerName = properties["TRACKERNAME"].front(); oneValueSet.append("TRACKERNAME"); } else - d->trackerName = String::null; + d->trackerName.clear(); // for each tag that has been set above, remove the first entry in the corresponding // value list. The others will be returned as unsupported by this format. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mod/modtag.h clementine-1.3.1-218/3rdparty/taglib/mod/modtag.h --- clementine-1.3.1-217/3rdparty/taglib/mod/modtag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mod/modtag.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MODTAG_H @@ -50,39 +54,39 @@ * Returns the track name; if no track name is present in the tag * String::null will be returned. */ - String title() const; + virtual String title() const; /*! * Not supported by module files. Therefore always returns String::null. */ - String artist() const; + virtual String artist() const; /*! * Not supported by module files. Therefore always returns String::null. */ - String album() const; + virtual String album() const; /*! * Returns the track comment derived from the instrument/sample/pattern * names; if no comment is present in the tag String::null will be * returned. */ - String comment() const; + virtual String comment() const; /*! * Not supported by module files. Therefore always returns String::null. */ - String genre() const; + virtual String genre() const; /*! * Not supported by module files. Therefore always returns 0. */ - uint year() const; + virtual unsigned int year() const; /*! * Not supported by module files. Therefore always returns 0. */ - uint track() const; + virtual unsigned int track() const; /*! * Returns the name of the tracker used to create/edit the module file. @@ -101,17 +105,17 @@ * Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 * characters. */ - void setTitle(const String &title); + virtual void setTitle(const String &title); /*! * Not supported by module files and therefore ignored. */ - void setArtist(const String &artist); + virtual void setArtist(const String &artist); /*! * Not supported by module files and therefore ignored. */ - void setAlbum(const String &album); + virtual void setAlbum(const String &album); /*! * Sets the comment to \a comment. If \a comment is String::null then @@ -130,22 +134,22 @@ * Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22 * characters. */ - void setComment(const String &comment); + virtual void setComment(const String &comment); /*! * Not supported by module files and therefore ignored. */ - void setGenre(const String &genre); + virtual void setGenre(const String &genre); /*! * Not supported by module files and therefore ignored. */ - void setYear(uint year); + virtual void setYear(unsigned int year); /*! * Not supported by module files and therefore ignored. */ - void setTrack(uint track); + virtual void setTrack(unsigned int track); /*! * Sets the tracker name to \a trackerName. If \a trackerName is diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4atom.cpp clementine-1.3.1-218/3rdparty/taglib/mp4/mp4atom.cpp --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4atom.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4atom.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include @@ -43,9 +39,11 @@ MP4::Atom::Atom(File *file) { + children.setAutoDelete(true); + offset = file->tell(); ByteVector header = file->readBlock(8); - if (header.size() != 8) { + if(header.size() != 8) { // The atom header must be 8 bytes long, otherwise there is either // trailing garbage or the file is truncated debug("MP4: Couldn't read 8 bytes of data for atom header"); @@ -94,7 +92,7 @@ while(file->tell() < offset + length) { MP4::Atom *child = new MP4::Atom(file); children.append(child); - if (child->length == 0) + if(child->length == 0) return; } return; @@ -106,10 +104,6 @@ MP4::Atom::~Atom() { - for(unsigned int i = 0; i < children.size(); i++) { - delete children[i]; - } - children.clear(); } MP4::Atom * @@ -118,9 +112,9 @@ if(name1 == 0) { return this; } - for(unsigned int i = 0; i < children.size(); i++) { - if(children[i]->name == name1) { - return children[i]->find(name2, name3, name4); + for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) { + if((*it)->name == name1) { + return (*it)->find(name2, name3, name4); } } return 0; @@ -130,12 +124,12 @@ MP4::Atom::findall(const char *name, bool recursive) { MP4::AtomList result; - for(unsigned int i = 0; i < children.size(); i++) { - if(children[i]->name == name) { - result.append(children[i]); + for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) { + if((*it)->name == name) { + result.append(*it); } if(recursive) { - result.append(children[i]->findall(name, recursive)); + result.append((*it)->findall(name, recursive)); } } return result; @@ -148,9 +142,9 @@ if(name1 == 0) { return true; } - for(unsigned int i = 0; i < children.size(); i++) { - if(children[i]->name == name1) { - return children[i]->path(path, name2, name3); + for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) { + if((*it)->name == name1) { + return (*it)->path(path, name2, name3); } } return false; @@ -158,6 +152,8 @@ MP4::Atoms::Atoms(File *file) { + atoms.setAutoDelete(true); + file->seek(0, File::End); long end = file->tell(); file->seek(0); @@ -171,18 +167,14 @@ MP4::Atoms::~Atoms() { - for(unsigned int i = 0; i < atoms.size(); i++) { - delete atoms[i]; - } - atoms.clear(); } MP4::Atom * MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4) { - for(unsigned int i = 0; i < atoms.size(); i++) { - if(atoms[i]->name == name1) { - return atoms[i]->find(name2, name3, name4); + for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) { + if((*it)->name == name1) { + return (*it)->find(name2, name3, name4); } } return 0; @@ -192,9 +184,9 @@ MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) { MP4::AtomList path; - for(unsigned int i = 0; i < atoms.size(); i++) { - if(atoms[i]->name == name1) { - if(!atoms[i]->path(path, name2, name3, name4)) { + for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) { + if((*it)->name == name1) { + if(!(*it)->path(path, name2, name3, name4)) { path.clear(); } return path; @@ -202,4 +194,3 @@ } return path; } - diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4atom.h clementine-1.3.1-218/3rdparty/taglib/mp4/mp4atom.h --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4atom.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4atom.h 2016-07-19 15:25:23.000000000 +0000 @@ -77,29 +77,29 @@ 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); - long offset; - long length; - TagLib::ByteVector name; - AtomList children; + 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); + long offset; + long length; + TagLib::ByteVector name; + AtomList children; private: - static const int numContainers = 11; - static const char *containers[11]; + static const int numContainers = 11; + static const char *containers[11]; }; //! Root-level atoms 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; + 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; }; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4coverart.cpp clementine-1.3.1-218/3rdparty/taglib/mp4/mp4coverart.cpp --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4coverart.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4coverart.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -33,20 +33,27 @@ class MP4::CoverArt::CoverArtPrivate : public RefCounter { public: - CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {} + CoverArtPrivate() : + RefCounter(), + format(MP4::CoverArt::JPEG) {} Format format; ByteVector data; }; -MP4::CoverArt::CoverArt(Format format, const ByteVector &data) +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MP4::CoverArt::CoverArt(Format format, const ByteVector &data) : + d(new CoverArtPrivate()) { - d = new CoverArtPrivate; d->format = format; d->data = data; } -MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d) +MP4::CoverArt::CoverArt(const CoverArt &item) : + d(item.d) { d->ref(); } @@ -54,15 +61,18 @@ MP4::CoverArt & MP4::CoverArt::operator=(const CoverArt &item) { - if(&item != this) { - if(d->deref()) - delete d; - d = item.d; - d->ref(); - } + CoverArt(item).swap(*this); return *this; } +void +MP4::CoverArt::swap(CoverArt &item) +{ + using std::swap; + + swap(d, item.d); +} + MP4::CoverArt::~CoverArt() { if(d->deref()) { @@ -81,4 +91,3 @@ { return d->data; } - diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4coverart.h clementine-1.3.1-218/3rdparty/taglib/mp4/mp4coverart.h --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4coverart.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4coverart.h 2016-07-19 15:25:23.000000000 +0000 @@ -53,8 +53,17 @@ ~CoverArt(); CoverArt(const CoverArt &item); + + /*! + * Copies the contents of \a item into this CoverArt. + */ CoverArt &operator=(const CoverArt &item); + /*! + * Exchanges the content of the CoverArt by the content of \a item. + */ + void swap(CoverArt &item); + //! Format of the image Format format() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4file.cpp clementine-1.3.1-218/3rdparty/taglib/mp4/mp4file.cpp --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4file.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4file.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -130,8 +130,7 @@ } // must have a moov atom, otherwise consider it invalid - MP4::Atom *moov = d->atoms->find("moov"); - if(!moov) { + if(!d->atoms->find("moov")) { setValid(false); return; } @@ -158,3 +157,8 @@ return d->tag->save(); } +bool +MP4::File::hasMP4Tag() const +{ + return (d->atoms->find("moov", "udta", "meta", "ilst") != 0); +} diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4file.h clementine-1.3.1-218/3rdparty/taglib/mp4/mp4file.h --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4file.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4file.h 2016-07-19 15:25:23.000000000 +0000 @@ -111,12 +111,15 @@ * Save the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the 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. + */ + bool hasMP4Tag() const; + private: void read(bool readProperties); diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4item.cpp clementine-1.3.1-218/3rdparty/taglib/mp4/mp4item.cpp --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4item.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4item.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -33,7 +33,10 @@ class MP4::Item::ItemPrivate : public RefCounter { public: - ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {} + ItemPrivate() : + RefCounter(), + valid(true), + atomDataType(TypeUndefined) {} bool valid; AtomDataType atomDataType; @@ -41,8 +44,8 @@ bool m_bool; int m_int; IntPair m_intPair; - uchar m_byte; - uint m_uint; + unsigned char m_byte; + unsigned int m_uint; long long m_longlong; }; StringList m_stringList; @@ -50,13 +53,14 @@ MP4::CoverArtList m_coverArtList; }; -MP4::Item::Item() +MP4::Item::Item() : + d(new ItemPrivate()) { - d = new ItemPrivate; d->valid = false; } -MP4::Item::Item(const Item &item) : d(item.d) +MP4::Item::Item(const Item &item) : + d(item.d) { d->ref(); } @@ -64,75 +68,76 @@ MP4::Item & MP4::Item::operator=(const Item &item) { - if(&item != this) { - if(d->deref()) { - delete d; - } - d = item.d; - d->ref(); - } + Item(item).swap(*this); return *this; } +void +MP4::Item::swap(Item &item) +{ + using std::swap; + + swap(d, item.d); +} + MP4::Item::~Item() { - if(d->deref()) { + if(d->deref()) delete d; - } } -MP4::Item::Item(bool value) +MP4::Item::Item(bool value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_bool = value; } -MP4::Item::Item(int value) +MP4::Item::Item(int value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_int = value; } -MP4::Item::Item(uchar value) +MP4::Item::Item(unsigned char value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_byte = value; } -MP4::Item::Item(uint value) +MP4::Item::Item(unsigned int value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_uint = value; } -MP4::Item::Item(long long value) +MP4::Item::Item(long long value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_longlong = value; } -MP4::Item::Item(int value1, int value2) +MP4::Item::Item(int value1, int value2) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_intPair.first = value1; d->m_intPair.second = value2; } -MP4::Item::Item(const ByteVectorList &value) +MP4::Item::Item(const ByteVectorList &value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_byteVectorList = value; } -MP4::Item::Item(const StringList &value) +MP4::Item::Item(const StringList &value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_stringList = value; } -MP4::Item::Item(const MP4::CoverArtList &value) +MP4::Item::Item(const MP4::CoverArtList &value) : + d(new ItemPrivate()) { - d = new ItemPrivate; d->m_coverArtList = value; } @@ -158,13 +163,13 @@ return d->m_int; } -uchar +unsigned char MP4::Item::toByte() const { return d->m_byte; } -TagLib::uint +unsigned int MP4::Item::toUInt() const { return d->m_uint; @@ -205,4 +210,3 @@ { return d->valid; } - diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4item.h clementine-1.3.1-218/3rdparty/taglib/mp4/mp4item.h --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4item.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4item.h 2016-07-19 15:25:23.000000000 +0000 @@ -43,12 +43,22 @@ Item(); Item(const Item &item); + + /*! + * Copies the contents of \a item into this Item. + */ Item &operator=(const Item &item); + + /*! + * Exchanges the content of the Item by the content of \a item. + */ + void swap(Item &item); + ~Item(); Item(int value); - Item(uchar value); - Item(uint value); + Item(unsigned char value); + Item(unsigned int value); Item(long long value); Item(bool value); Item(int first, int second); @@ -60,8 +70,8 @@ AtomDataType atomDataType() const; int toInt() const; - uchar toByte() const; - uint toUInt() const; + unsigned char toByte() const; + unsigned int toUInt() const; long long toLongLong() const; bool toBool() const; IntPair toIntPair() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4properties.cpp clementine-1.3.1-218/3rdparty/taglib/mp4/mp4properties.cpp --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4properties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4properties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -167,7 +167,7 @@ file->seek(mdhd->offset); data = file->readBlock(mdhd->length); - const uint version = data[8]; + const unsigned int version = data[8]; long long unit; long long length; if(version == 1) { @@ -187,7 +187,7 @@ length = data.toUInt(24U); } if(unit > 0 && length > 0) - d->length = static_cast(length * 1000.0 / unit); + d->length = static_cast(length * 1000.0 / unit + 0.5); MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd"); if(!atom) { @@ -202,7 +202,7 @@ d->bitsPerSample = data.toShort(42U); d->sampleRate = data.toUInt(46U); if(data.containsAt("esds", 56) && data[64] == 0x03) { - uint pos = 65; + unsigned int pos = 65; if(data.containsAt("\x80\x80\x80", pos)) { pos += 3; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4tag.cpp clementine-1.3.1-218/3rdparty/taglib/mp4/mp4tag.cpp --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4tag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4tag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -35,21 +35,23 @@ class MP4::Tag::TagPrivate { public: - TagPrivate() : file(0), atoms(0) {} - ~TagPrivate() {} + TagPrivate() : + file(0), + atoms(0) {} + TagLib::File *file; Atoms *atoms; ItemMap items; }; -MP4::Tag::Tag() +MP4::Tag::Tag() : + d(new TagPrivate()) { - d = new TagPrivate; } -MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) +MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) : + d(new TagPrivate()) { - d = new TagPrivate; d->file = file; d->atoms = atoms; @@ -59,8 +61,8 @@ return; } - for(unsigned int i = 0; i < ilst->children.size(); i++) { - MP4::Atom *atom = ilst->children[i]; + for(AtomList::ConstIterator it = ilst->children.begin(); it != ilst->children.end(); ++it) { + MP4::Atom *atom = *it; file->seek(atom->offset + 8); if(atom->name == "----") { parseFreeForm(atom); @@ -149,8 +151,8 @@ { AtomDataList data = parseData2(atom, expectedFlags, freeForm); ByteVectorList result; - for(uint i = 0; i < data.size(); i++) { - result.append(data[i].data); + for(AtomDataList::ConstIterator it = data.begin(); it != data.end(); ++it) { + result.append(it->data); } return result; } @@ -159,7 +161,7 @@ MP4::Tag::parseInt(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { + if(!data.isEmpty()) { addItem(atom->name, (int)data[0].toShort()); } } @@ -168,7 +170,7 @@ MP4::Tag::parseUInt(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { + if(!data.isEmpty()) { addItem(atom->name, data[0].toUInt()); } } @@ -177,7 +179,7 @@ MP4::Tag::parseLongLong(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { + if(!data.isEmpty()) { addItem(atom->name, data[0].toLongLong()); } } @@ -186,8 +188,8 @@ MP4::Tag::parseByte(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { - addItem(atom->name, (uchar)data[0].at(0)); + if(!data.isEmpty()) { + addItem(atom->name, static_cast(data[0].at(0))); } } @@ -195,7 +197,7 @@ MP4::Tag::parseGnre(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { + if(!data.isEmpty()) { int idx = (int)data[0].toShort(); if(idx > 0) { addItem("\251gen", StringList(ID3v1::genre(idx - 1))); @@ -207,7 +209,7 @@ MP4::Tag::parseIntPair(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { + if(!data.isEmpty()) { const int a = data[0].toShort(2U); const int b = data[0].toShort(4U); addItem(atom->name, MP4::Item(a, b)); @@ -218,7 +220,7 @@ MP4::Tag::parseBool(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); - if(data.size()) { + if(!data.isEmpty()) { bool value = data[0].size() ? data[0][0] != '\0' : false; addItem(atom->name, value); } @@ -228,10 +230,10 @@ MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) { ByteVectorList data = parseData(atom, expectedFlags); - if(data.size()) { + if(!data.isEmpty()) { StringList value; - for(unsigned int i = 0; i < data.size(); i++) { - value.append(String(data[i], String::UTF8)); + for(ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) { + value.append(String(*it, String::UTF8)); } addItem(atom->name, value); } @@ -242,18 +244,25 @@ { AtomDataList data = parseData2(atom, -1, true); if(data.size() > 2) { - String name = "----:" + String(data[0].data, String::UTF8) + ':' + String(data[1].data, String::UTF8); - AtomDataType type = data[2].type; - for(uint i = 2; i < data.size(); i++) { - if(data[i].type != type) { + AtomDataList::ConstIterator itBegin = data.begin(); + + String name = "----:"; + name += String((itBegin++)->data, String::UTF8); // data[0].data + name += ':'; + name += String((itBegin++)->data, String::UTF8); // data[1].data + + AtomDataType type = itBegin->type; // data[2].type + + for(AtomDataList::ConstIterator it = itBegin; it != data.end(); ++it) { + if(it->type != type) { debug("MP4: We currently don't support values with multiple types"); break; } } if(type == TypeUTF8) { StringList value; - for(uint i = 2; i < data.size(); i++) { - value.append(String(data[i].data, String::UTF8)); + for(AtomDataList::ConstIterator it = itBegin; it != data.end(); ++it) { + value.append(String(it->data, String::UTF8)); } Item item(value); item.setAtomDataType(type); @@ -261,8 +270,8 @@ } else { ByteVectorList value; - for(uint i = 2; i < data.size(); i++) { - value.append(data[i].data); + for(AtomDataList::ConstIterator it = itBegin; it != data.end(); ++it) { + value.append(it->data); } Item item(value); item.setAtomDataType(type); @@ -300,7 +309,7 @@ } pos += length; } - if(value.size() > 0) + if(!value.isEmpty()) addItem(atom->name, value); } @@ -323,8 +332,8 @@ MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const { ByteVector result; - for(unsigned int i = 0; i < data.size(); i++) { - result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i])); + 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); } @@ -395,8 +404,8 @@ { ByteVectorList data; StringList value = item.toStringList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(value[i].data(String::UTF8)); + for(StringList::ConstIterator it = value.begin(); it != value.end(); ++it) { + data.append(it->data(String::UTF8)); } return renderData(name, flags, data); } @@ -406,9 +415,9 @@ { ByteVector data; MP4::CoverArtList value = item.toCoverArtList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(renderAtom("data", ByteVector::fromUInt(value[i].format()) + - ByteVector(4, '\0') + value[i].data())); + 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); } @@ -417,9 +426,9 @@ MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const { StringList header = StringList::split(name, ":"); - if (header.size() != 3) { + if(header.size() != 3) { debug("MP4: Invalid free-form item name \"" + name + "\""); - return ByteVector::null; + return ByteVector(); } ByteVector data; data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8))); @@ -435,14 +444,14 @@ } if(type == TypeUTF8) { StringList value = item.toStringList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i].data(String::UTF8))); + for(StringList::ConstIterator it = value.begin(); it != value.end(); ++it) { + data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + it->data(String::UTF8))); } } else { ByteVectorList value = item.toByteVectorList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i])); + for(ByteVectorList::ConstIterator it = value.begin(); it != value.end(); ++it) { + data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + *it)); } } return renderAtom("----", data); @@ -505,20 +514,26 @@ void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) { - for(unsigned int i = 0; i < path.size() - ignore; i++) { - d->file->seek(path[i]->offset); + if(static_cast(path.size()) <= ignore) + return; + + AtomList::ConstIterator itEnd = path.end(); + std::advance(itEnd, 0 - ignore); + + for(AtomList::ConstIterator it = path.begin(); it != itEnd; ++it) { + d->file->seek((*it)->offset); long size = d->file->readBlock(4).toUInt(); // 64-bit if (size == 1) { d->file->seek(4, File::Current); // Skip name long long longSize = d->file->readBlock(8).toLongLong(); // Seek the offset of the 64-bit size - d->file->seek(path[i]->offset + 8); + d->file->seek((*it)->offset + 8); d->file->writeBlock(ByteVector::fromLongLong(longSize + delta)); } // 32-bit else { - d->file->seek(path[i]->offset); + d->file->seek((*it)->offset); d->file->writeBlock(ByteVector::fromUInt(size + delta)); } } @@ -530,8 +545,8 @@ MP4::Atom *moov = d->atoms->find("moov"); if(moov) { MP4::AtomList stco = moov->findall("stco", true); - for(unsigned int i = 0; i < stco.size(); i++) { - MP4::Atom *atom = stco[i]; + for(MP4::AtomList::ConstIterator it = stco.begin(); it != stco.end(); ++it) { + MP4::Atom *atom = *it; if(atom->offset > offset) { atom->offset += delta; } @@ -539,7 +554,7 @@ ByteVector data = d->file->readBlock(atom->length - 12); unsigned int count = data.toUInt(); d->file->seek(atom->offset + 16); - uint pos = 4; + unsigned int pos = 4; while(count--) { long o = static_cast(data.toUInt(pos)); if(o > offset) { @@ -551,8 +566,8 @@ } MP4::AtomList co64 = moov->findall("co64", true); - for(unsigned int i = 0; i < co64.size(); i++) { - MP4::Atom *atom = co64[i]; + for(MP4::AtomList::ConstIterator it = co64.begin(); it != co64.end(); ++it) { + MP4::Atom *atom = *it; if(atom->offset > offset) { atom->offset += delta; } @@ -560,7 +575,7 @@ ByteVector data = d->file->readBlock(atom->length - 12); unsigned int count = data.toUInt(); d->file->seek(atom->offset + 16); - uint pos = 4; + unsigned int pos = 4; while(count--) { long long o = data.toLongLong(pos); if(o > offset) { @@ -575,8 +590,8 @@ MP4::Atom *moof = d->atoms->find("moof"); if(moof) { MP4::AtomList tfhd = moof->findall("tfhd", true); - for(unsigned int i = 0; i < tfhd.size(); i++) { - MP4::Atom *atom = tfhd[i]; + for(MP4::AtomList::ConstIterator it = tfhd.begin(); it != tfhd.end(); ++it) { + MP4::Atom *atom = *it; if(atom->offset > offset) { atom->offset += delta; } @@ -609,21 +624,28 @@ data = renderAtom("udta", data); } - long offset = path[path.size() - 1]->offset + 8; + long offset = path.back()->offset + 8; d->file->insert(data, offset, 0); updateParents(path, data.size()); updateOffsets(data.size(), offset); + + // Insert the newly created atoms into the tree to keep it up-to-date. + + d->file->seek(offset); + path.back()->children.prepend(new Atom(d->file)); } void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) { - MP4::Atom *ilst = path[path.size() - 1]; + AtomList::ConstIterator it = path.end(); + + MP4::Atom *ilst = *(--it); long offset = ilst->offset; long length = ilst->length; - MP4::Atom *meta = path[path.size() - 2]; + MP4::Atom *meta = *(--it); AtomList::ConstIterator index = meta->children.find(ilst); // check if there is an atom before 'ilst', and possibly use it as padding @@ -669,7 +691,7 @@ { if(d->items.contains("\251nam")) return d->items["\251nam"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -677,7 +699,7 @@ { if(d->items.contains("\251ART")) return d->items["\251ART"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -685,7 +707,7 @@ { if(d->items.contains("\251alb")) return d->items["\251alb"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -693,7 +715,7 @@ { if(d->items.contains("\251cmt")) return d->items["\251cmt"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -701,7 +723,7 @@ { if(d->items.contains("\251gen")) return d->items["\251gen"].toStringList().toString(", "); - return String::null; + return String(); } unsigned int @@ -751,13 +773,13 @@ } void -MP4::Tag::setYear(uint value) +MP4::Tag::setYear(unsigned int value) { d->items["\251day"] = StringList(String::number(value)); } void -MP4::Tag::setTrack(uint value) +MP4::Tag::setTrack(unsigned int value) { d->items["trkn"] = MP4::Item(value, 0); } @@ -797,71 +819,76 @@ return d->items.contains(key); } -static const char *keyTranslation[][2] = { - { "\251nam", "TITLE" }, - { "\251ART", "ARTIST" }, - { "\251alb", "ALBUM" }, - { "\251cmt", "COMMENT" }, - { "\251gen", "GENRE" }, - { "\251day", "DATE" }, - { "\251wrt", "COMPOSER" }, - { "\251grp", "GROUPING" }, - { "aART", "ALBUMARTIST" }, - { "trkn", "TRACKNUMBER" }, - { "disk", "DISCNUMBER" }, - { "cpil", "COMPILATION" }, - { "tmpo", "BPM" }, - { "cprt", "COPYRIGHT" }, - { "\251lyr", "LYRICS" }, - { "\251too", "ENCODEDBY" }, - { "soal", "ALBUMSORT" }, - { "soaa", "ALBUMARTISTSORT" }, - { "soar", "ARTISTSORT" }, - { "sonm", "TITLESORT" }, - { "soco", "COMPOSERSORT" }, - { "sosn", "SHOWSORT" }, - { "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" }, - { "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, - { "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, - { "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, - { "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, - { "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, - { "----:com.apple.iTunes:ASIN", "ASIN" }, - { "----:com.apple.iTunes:LABEL", "LABEL" }, - { "----:com.apple.iTunes:LYRICIST", "LYRICIST" }, - { "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" }, - { "----:com.apple.iTunes:REMIXER", "REMIXER" }, - { "----:com.apple.iTunes:ENGINEER", "ENGINEER" }, - { "----:com.apple.iTunes:PRODUCER", "PRODUCER" }, - { "----:com.apple.iTunes:DJMIXER", "DJMIXER" }, - { "----:com.apple.iTunes:MIXER", "MIXER" }, - { "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" }, - { "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" }, - { "----:com.apple.iTunes:MOOD", "MOOD" }, - { "----:com.apple.iTunes:ISRC", "ISRC" }, - { "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" }, - { "----:com.apple.iTunes:BARCODE", "BARCODE" }, - { "----:com.apple.iTunes:SCRIPT", "SCRIPT" }, - { "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" }, - { "----:com.apple.iTunes:LICENSE", "LICENSE" }, - { "----:com.apple.iTunes:MEDIA", "MEDIA" }, -}; - -PropertyMap MP4::Tag::properties() const +namespace { - static Map keyMap; - if(keyMap.isEmpty()) { - int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); - for(int i = 0; i < numKeys; i++) { - keyMap[keyTranslation[i][0]] = keyTranslation[i][1]; + const char *keyTranslation[][2] = { + { "\251nam", "TITLE" }, + { "\251ART", "ARTIST" }, + { "\251alb", "ALBUM" }, + { "\251cmt", "COMMENT" }, + { "\251gen", "GENRE" }, + { "\251day", "DATE" }, + { "\251wrt", "COMPOSER" }, + { "\251grp", "GROUPING" }, + { "aART", "ALBUMARTIST" }, + { "trkn", "TRACKNUMBER" }, + { "disk", "DISCNUMBER" }, + { "cpil", "COMPILATION" }, + { "tmpo", "BPM" }, + { "cprt", "COPYRIGHT" }, + { "\251lyr", "LYRICS" }, + { "\251too", "ENCODEDBY" }, + { "soal", "ALBUMSORT" }, + { "soaa", "ALBUMARTISTSORT" }, + { "soar", "ARTISTSORT" }, + { "sonm", "TITLESORT" }, + { "soco", "COMPOSERSORT" }, + { "sosn", "SHOWSORT" }, + { "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" }, + { "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, + { "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, + { "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, + { "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, + { "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, + { "----:com.apple.iTunes:ASIN", "ASIN" }, + { "----:com.apple.iTunes:LABEL", "LABEL" }, + { "----:com.apple.iTunes:LYRICIST", "LYRICIST" }, + { "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" }, + { "----:com.apple.iTunes:REMIXER", "REMIXER" }, + { "----:com.apple.iTunes:ENGINEER", "ENGINEER" }, + { "----:com.apple.iTunes:PRODUCER", "PRODUCER" }, + { "----:com.apple.iTunes:DJMIXER", "DJMIXER" }, + { "----:com.apple.iTunes:MIXER", "MIXER" }, + { "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" }, + { "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" }, + { "----:com.apple.iTunes:MOOD", "MOOD" }, + { "----:com.apple.iTunes:ISRC", "ISRC" }, + { "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" }, + { "----:com.apple.iTunes:BARCODE", "BARCODE" }, + { "----:com.apple.iTunes:SCRIPT", "SCRIPT" }, + { "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" }, + { "----:com.apple.iTunes:LICENSE", "LICENSE" }, + { "----:com.apple.iTunes:MEDIA", "MEDIA" }, + }; + 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(); } +} +PropertyMap MP4::Tag::properties() const +{ PropertyMap props; - MP4::ItemMap::ConstIterator it = d->items.begin(); - for(; it != d->items.end(); ++it) { - if(keyMap.contains(it->first)) { - String key = keyMap[it->first]; + for(MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) { + const String key = translateKey(it->first); + if(!key.isEmpty()) { if(key == "TRACKNUMBER" || key == "DISCNUMBER") { MP4::Item::IntPair ip = it->second.toIntPair(); String value = String::number(ip.first); @@ -889,8 +916,7 @@ void MP4::Tag::removeUnsupportedProperties(const StringList &props) { - StringList::ConstIterator it = props.begin(); - for(; it != props.end(); ++it) + for(StringList::ConstIterator it = props.begin(); it != props.end(); ++it) d->items.erase(*it); } @@ -905,22 +931,20 @@ } PropertyMap origProps = properties(); - PropertyMap::ConstIterator it = origProps.begin(); - for(; it != origProps.end(); ++it) { + for(PropertyMap::ConstIterator it = origProps.begin(); it != origProps.end(); ++it) { if(!props.contains(it->first) || props[it->first].isEmpty()) { d->items.erase(reverseKeyMap[it->first]); } } PropertyMap ignoredProps; - it = props.begin(); - for(; it != props.end(); ++it) { + for(PropertyMap::ConstIterator it = props.begin(); it != props.end(); ++it) { if(reverseKeyMap.contains(it->first)) { String name = reverseKeyMap[it->first]; if((it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") && !it->second.isEmpty()) { int first = 0, second = 0; StringList parts = StringList::split(it->second.front(), "/"); - if(parts.size() > 0) { + if(!parts.isEmpty()) { first = parts[0].toInt(); if(parts.size() > 1) { second = parts[1].toInt(); diff -Nru clementine-1.3.1-217/3rdparty/taglib/mp4/mp4tag.h clementine-1.3.1-218/3rdparty/taglib/mp4/mp4tag.h --- clementine-1.3.1-217/3rdparty/taglib/mp4/mp4tag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mp4/mp4tag.h 2016-07-19 15:25:23.000000000 +0000 @@ -50,24 +50,24 @@ public: Tag(); Tag(TagLib::File *file, Atoms *atoms); - ~Tag(); + virtual ~Tag(); bool save(); - String title() const; - String artist() const; - String album() const; - String comment() const; - String genre() const; - uint year() const; - uint track() const; + virtual String title() const; + virtual String artist() const; + virtual String album() const; + virtual String comment() const; + virtual String genre() const; + virtual unsigned int year() const; + virtual unsigned int track() const; - void setTitle(const String &value); - void setArtist(const String &value); - void setAlbum(const String &value); - void setComment(const String &value); - void setGenre(const String &value); - void setYear(uint value); - void setTrack(uint value); + virtual void setTitle(const String &value); + virtual void setArtist(const String &value); + virtual void setAlbum(const String &value); + virtual void setComment(const String &value); + virtual void setGenre(const String &value); + virtual void setYear(unsigned int value); + virtual void setTrack(unsigned int value); virtual bool isEmpty() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpc/mpcfile.cpp clementine-1.3.1-218/3rdparty/taglib/mpc/mpcfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpc/mpcfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpc/mpcfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include "mpcfile.h" #include "id3v1tag.h" @@ -52,10 +53,7 @@ ID3v2Header(0), ID3v2Location(-1), ID3v2Size(0), - properties(0), - hasAPE(false), - hasID3v1(false), - hasID3v2(false) {} + properties(0) {} ~FilePrivate() { @@ -64,24 +62,17 @@ } long APELocation; - uint APESize; + long APESize; long ID3v1Location; ID3v2::Header *ID3v2Header; long ID3v2Location; - uint ID3v2Size; + long ID3v2Size; TagUnion tag; Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasAPE; - bool hasID3v1; - bool hasID3v2; }; //////////////////////////////////////////////////////////////////////////////// @@ -116,26 +107,20 @@ PropertyMap MPC::File::properties() const { - if(d->hasAPE) - return d->tag.access(MPCAPEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access(MPCID3v1Index, false)->properties(); - return PropertyMap(); + return d->tag.properties(); } void MPC::File::removeUnsupportedProperties(const StringList &properties) { - if(d->hasAPE) - d->tag.access(MPCAPEIndex, false)->removeUnsupportedProperties(properties); - if(d->hasID3v1) - d->tag.access(MPCID3v1Index, false)->removeUnsupportedProperties(properties); + d->tag.removeUnsupportedProperties(properties); } PropertyMap MPC::File::setProperties(const PropertyMap &properties) { - if(d->hasID3v1) - d->tag.access(MPCID3v1Index, false)->setProperties(properties); - return d->tag.access(MPCAPEIndex, true)->setProperties(properties); + if(ID3v1Tag()) + ID3v1Tag()->setProperties(properties); + + return APETag(true)->setProperties(properties); } MPC::Properties *MPC::File::audioProperties() const @@ -152,69 +137,80 @@ // Possibly strip ID3v2 tag - if(d->hasID3v2 && !d->ID3v2Header) { + if(!d->ID3v2Header && d->ID3v2Location >= 0) { removeBlock(d->ID3v2Location, d->ID3v2Size); - d->hasID3v2 = false; - if(d->hasID3v1) - d->ID3v1Location -= d->ID3v2Size; - if(d->hasAPE) + + if(d->APELocation >= 0) d->APELocation -= d->ID3v2Size; + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->ID3v2Size; + + d->ID3v2Location = -1; + d->ID3v2Size = 0; } // Update ID3v1 tag - if(ID3v1Tag()) { - if(d->hasID3v1) { + if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { + + // ID3v1 tag is not empty. Update the old one or create a new one. + + if(d->ID3v1Location >= 0) { seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); } else { seek(0, End); d->ID3v1Location = tell(); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; } - } else - if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->hasID3v1 = false; - if(d->hasAPE) { - if(d->APELocation > d->ID3v1Location) - d->APELocation -= 128; - } + + writeBlock(ID3v1Tag()->render()); + } + else { + + // ID3v1 tag is empty. Remove the old one. + + if(d->ID3v1Location >= 0) { + truncate(d->ID3v1Location); + d->ID3v1Location = -1; } + } // Update APE tag - if(APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APESize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; + if(APETag() && !APETag()->isEmpty()) { + + // APE tag is not empty. Update the old one or create a new one. + + if(d->APELocation < 0) { + if(d->ID3v1Location >= 0) d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APESize; - } - else { - seek(0, End); - d->APELocation = tell(); - writeBlock(APETag()->render()); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } + else + d->APELocation = length(); } + + const ByteVector data = APETag()->render(); + insert(data, d->APELocation, d->APESize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->APESize); + + d->APESize = data.size(); } - else - if(d->hasAPE) { + else { + + // APE tag is empty. Remove the old one. + + if(d->APELocation >= 0) { removeBlock(d->APELocation, d->APESize); - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) - d->ID3v1Location -= d->APESize; - } + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->APESize; + + d->APELocation = -1; + d->APESize = 0; } + } return true; } @@ -231,22 +227,19 @@ void MPC::File::strip(int tags) { - if(tags & ID3v1) { + if(tags & ID3v1) d->tag.set(MPCID3v1Index, 0); + + if(tags & APE) + d->tag.set(MPCAPEIndex, 0); + + if(!ID3v1Tag()) APETag(true); - } if(tags & ID3v2) { delete d->ID3v2Header; d->ID3v2Header = 0; } - - if(tags & APE) { - d->tag.set(MPCAPEIndex, 0); - - if(!ID3v1Tag()) - APETag(true); - } } void MPC::File::remove(int tags) @@ -256,12 +249,12 @@ bool MPC::File::hasID3v1Tag() const { - return d->hasID3v1; + return (d->ID3v1Location >= 0); } bool MPC::File::hasAPETag() const { - return d->hasAPE; + return (d->APELocation >= 0); } //////////////////////////////////////////////////////////////////////////////// @@ -270,55 +263,50 @@ void MPC::File::read(bool readProperties) { + // Look for an ID3v2 tag + + d->ID3v2Location = Utils::findID3v2(this); + + if(d->ID3v2Location >= 0) { + seek(d->ID3v2Location); + d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); + d->ID3v2Size = d->ID3v2Header->completeTagSize(); + } + // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); - if(d->ID3v1Location >= 0) { + if(d->ID3v1Location >= 0) d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } // Look for an APE tag - d->APELocation = findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation)); - d->APESize = APETag()->footer()->completeTagSize(); - d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; - d->hasAPE = true; + d->APELocation = d->APELocation + APE::Footer::size() - d->APESize; } - if(!d->hasID3v1) + if(d->ID3v1Location < 0) APETag(true); - // Look for an ID3v2 tag - - d->ID3v2Location = findID3v2(); - - if(d->ID3v2Location >= 0) { - seek(d->ID3v2Location); - d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); - d->ID3v2Size = d->ID3v2Header->completeTagSize(); - d->hasID3v2 = true; - } - // Look for MPC metadata if(readProperties) { long streamLength; - if(d->hasAPE) + if(d->APELocation >= 0) streamLength = d->APELocation; - else if(d->hasID3v1) + else if(d->ID3v1Location >= 0) streamLength = d->ID3v1Location; else streamLength = length(); - if(d->hasID3v2) { + if(d->ID3v2Location >= 0) { seek(d->ID3v2Location + d->ID3v2Size); streamLength -= (d->ID3v2Location + d->ID3v2Size); } @@ -329,48 +317,3 @@ d->properties = new Properties(this, streamLength); } } - -long MPC::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -long MPC::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long MPC::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpc/mpcfile.h clementine-1.3.1-218/3rdparty/taglib/mpc/mpcfile.h --- clementine-1.3.1-217/3rdparty/taglib/mpc/mpcfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpc/mpcfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -141,9 +141,6 @@ * Saves the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ virtual bool save(); @@ -222,9 +219,6 @@ File &operator=(const File &); void read(bool readProperties); - long findAPE(); - long findID3v1(); - long findID3v2(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpc/mpcproperties.cpp clementine-1.3.1-218/3rdparty/taglib/mpc/mpcproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpc/mpcproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpc/mpcproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -49,18 +49,18 @@ albumGain(0), albumPeak(0) {} - int version; - int length; - int bitrate; - int sampleRate; - int channels; - uint totalFrames; - uint sampleFrames; - uint trackGain; - uint trackPeak; - uint albumGain; - uint albumPeak; - String flags; + int version; + int length; + int bitrate; + int sampleRate; + int channels; + unsigned int totalFrames; + unsigned int sampleFrames; + unsigned int trackGain; + unsigned int trackPeak; + unsigned int albumGain; + unsigned int albumPeak; + String flags; }; //////////////////////////////////////////////////////////////////////////////// @@ -129,12 +129,12 @@ return d->version; } -TagLib::uint MPC::Properties::totalFrames() const +unsigned int MPC::Properties::totalFrames() const { return d->totalFrames; } -TagLib::uint MPC::Properties::sampleFrames() const +unsigned int MPC::Properties::sampleFrames() const { return d->sampleFrames; } @@ -163,42 +163,42 @@ // private members //////////////////////////////////////////////////////////////////////////////// -unsigned long readSize(File *file, TagLib::uint &sizeLength, bool &eof) +namespace { - sizeLength = 0; - eof = false; - - unsigned char tmp; - unsigned long size = 0; + unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) + { + sizeLength = 0; + eof = false; + + unsigned char tmp; + unsigned long size = 0; + + do { + const ByteVector b = file->readBlock(1); + if(b.isEmpty()) { + eof = true; + break; + } - do { - const ByteVector b = file->readBlock(1); - if(b.isEmpty()) { - eof = true; - break; - } + tmp = b[0]; + size = (size << 7) | (tmp & 0x7F); + sizeLength++; + } while((tmp & 0x80)); + return size; + } - tmp = b[0]; - size = (size << 7) | (tmp & 0x7F); - sizeLength++; - } while((tmp & 0x80)); - return size; -} - -unsigned long readSize(const ByteVector &data, TagLib::uint &pos) -{ - unsigned char tmp; - unsigned long size = 0; - - do { - tmp = data[pos++]; - size = (size << 7) | (tmp & 0x7F); - } while((tmp & 0x80) && (pos < data.size())); - 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())); + return size; + } -namespace -{ // This array looks weird, but the same as original MusePack code found at: // https://www.musepack.net/index.php?pg=src const unsigned short sftable [8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 }; @@ -211,7 +211,7 @@ while(!readSH && !readRG) { const ByteVector packetType = file->readBlock(2); - uint packetSizeLength; + unsigned int packetSizeLength; bool eof; const unsigned long packetSize = readSize(file, packetSizeLength, eof); if(eof) { @@ -238,7 +238,7 @@ readSH = true; - TagLib::uint pos = 4; + unsigned int pos = 4; d->version = data[pos]; pos += 1; d->sampleFrames = readSize(data, pos); @@ -247,19 +247,19 @@ break; } - const ulong begSilence = readSize(data, pos); + const unsigned long begSilence = readSize(data, pos); if(pos > dataSize - 2) { debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt."); break; } - const ushort flags = data.toUShort(pos, true); + const unsigned short flags = data.toUShort(pos, true); pos += 2; d->sampleRate = sftable[(flags >> 13) & 0x07]; d->channels = ((flags >> 4) & 0x0F) + 1; - const uint frameCount = d->sampleFrames - begSilence; + const unsigned int frameCount = d->sampleFrames - begSilence; if(frameCount > 0 && d->sampleRate > 0) { const double length = frameCount * 1000.0 / d->sampleRate; d->length = static_cast(length + 0.5); @@ -305,11 +305,11 @@ d->totalFrames = data.toUInt(4, false); - const uint flags = data.toUInt(8, false); + const unsigned int flags = data.toUInt(8, false); d->sampleRate = sftable[(flags >> 16) & 0x03]; d->channels = 2; - const uint gapless = data.toUInt(5, false); + const unsigned int gapless = data.toUInt(5, false); d->trackGain = data.toShort(14, false); d->trackPeak = data.toShort(12, false); @@ -337,14 +337,14 @@ bool trueGapless = (gapless >> 31) & 0x0001; if(trueGapless) { - uint lastFrameSamples = (gapless >> 20) & 0x07FF; + unsigned int lastFrameSamples = (gapless >> 20) & 0x07FF; d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples; } else d->sampleFrames = d->totalFrames * 1152 - 576; } else { - const uint headerData = data.toUInt(0, false); + const unsigned int headerData = data.toUInt(0, false); d->bitrate = (headerData >> 23) & 0x01ff; d->version = (headerData >> 11) & 0x03ff; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpc/mpcproperties.h clementine-1.3.1-218/3rdparty/taglib/mpc/mpcproperties.h --- clementine-1.3.1-217/3rdparty/taglib/mpc/mpcproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpc/mpcproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -35,7 +35,7 @@ class File; - static const uint HeaderSize = 8*7; + static const unsigned int HeaderSize = 8 * 7; //! An implementation of audio property reading for MPC @@ -113,8 +113,8 @@ */ int mpcVersion() const; - uint totalFrames() const; - uint sampleFrames() const; + unsigned int totalFrames() const; + unsigned int sampleFrames() const; /*! * Returns the track gain as an integer value, diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -27,237 +27,239 @@ using namespace TagLib; -namespace TagLib { - namespace ID3v1 { - - static const int genresSize = 192; - static const String genres[] = { - "Blues", - "Classic Rock", - "Country", - "Dance", - "Disco", - "Funk", - "Grunge", - "Hip-Hop", - "Jazz", - "Metal", - "New Age", - "Oldies", - "Other", - "Pop", - "R&B", - "Rap", - "Reggae", - "Rock", - "Techno", - "Industrial", - "Alternative", - "Ska", - "Death Metal", - "Pranks", - "Soundtrack", - "Euro-Techno", - "Ambient", - "Trip-Hop", - "Vocal", - "Jazz+Funk", - "Fusion", - "Trance", - "Classical", - "Instrumental", - "Acid", - "House", - "Game", - "Sound Clip", - "Gospel", - "Noise", - "Alternative Rock", - "Bass", - "Soul", - "Punk", - "Space", - "Meditative", - "Instrumental Pop", - "Instrumental Rock", - "Ethnic", - "Gothic", - "Darkwave", - "Techno-Industrial", - "Electronic", - "Pop-Folk", - "Eurodance", - "Dream", - "Southern Rock", - "Comedy", - "Cult", - "Gangsta", - "Top 40", - "Christian Rap", - "Pop/Funk", - "Jungle", - "Native American", - "Cabaret", - "New Wave", - "Psychedelic", - "Rave", - "Showtunes", - "Trailer", - "Lo-Fi", - "Tribal", - "Acid Punk", - "Acid Jazz", - "Polka", - "Retro", - "Musical", - "Rock & Roll", - "Hard Rock", - "Folk", - "Folk/Rock", - "National Folk", - "Swing", - "Fusion", - "Bebob", - "Latin", - "Revival", - "Celtic", - "Bluegrass", - "Avantgarde", - "Gothic Rock", - "Progressive Rock", - "Psychedelic Rock", - "Symphonic Rock", - "Slow Rock", - "Big Band", - "Chorus", - "Easy Listening", - "Acoustic", - "Humour", - "Speech", - "Chanson", - "Opera", - "Chamber Music", - "Sonata", - "Symphony", - "Booty Bass", - "Primus", - "Porn Groove", - "Satire", - "Slow Jam", - "Club", - "Tango", - "Samba", - "Folklore", - "Ballad", - "Power Ballad", - "Rhythmic Soul", - "Freestyle", - "Duet", - "Punk Rock", - "Drum Solo", - "A Cappella", - "Euro-House", - "Dance Hall", - "Goa", - "Drum & Bass", - "Club-House", - "Hardcore", - "Terror", - "Indie", - "BritPop", - "Negerpunk", - "Polsk Punk", - "Beat", - "Christian Gangsta Rap", - "Heavy Metal", - "Black Metal", - "Crossover", - "Contemporary Christian", - "Christian Rock", - "Merengue", - "Salsa", - "Thrash Metal", - "Anime", - "Jpop", - "Synthpop", - "Abstract", - "Art Rock", - "Baroque", - "Bhangra", - "Big Beat", - "Breakbeat", - "Chillout", - "Downtempo", - "Dub", - "EBM", - "Eclectic", - "Electro", - "Electroclash", - "Emo", - "Experimental", - "Garage", - "Global", - "IDM", - "Illbient", - "Industro-Goth", - "Jam Band", - "Krautrock", - "Leftfield", - "Lounge", - "Math Rock", - "New Romantic", - "Nu-Breakz", - "Post-Punk", - "Post-Rock", - "Psytrance", - "Shoegaze", - "Space Rock", - "Trop Rock", - "World Music", - "Neoclassical", - "Audiobook", - "Audio Theatre", - "Neue Deutsche Welle", - "Podcast", - "Indie Rock", - "G-Funk", - "Dubstep", - "Garage Rock", - "Psybient" - }; - } +namespace +{ + const wchar_t *genres[] = { + L"Blues", + L"Classic Rock", + L"Country", + L"Dance", + L"Disco", + L"Funk", + L"Grunge", + L"Hip-Hop", + L"Jazz", + L"Metal", + L"New Age", + L"Oldies", + L"Other", + L"Pop", + L"R&B", + L"Rap", + L"Reggae", + L"Rock", + L"Techno", + L"Industrial", + L"Alternative", + L"Ska", + L"Death Metal", + L"Pranks", + L"Soundtrack", + L"Euro-Techno", + L"Ambient", + L"Trip-Hop", + L"Vocal", + L"Jazz+Funk", + L"Fusion", + L"Trance", + L"Classical", + L"Instrumental", + L"Acid", + L"House", + L"Game", + L"Sound Clip", + L"Gospel", + L"Noise", + L"Alternative Rock", + L"Bass", + L"Soul", + L"Punk", + L"Space", + L"Meditative", + L"Instrumental Pop", + L"Instrumental Rock", + L"Ethnic", + L"Gothic", + L"Darkwave", + L"Techno-Industrial", + L"Electronic", + L"Pop-Folk", + L"Eurodance", + L"Dream", + L"Southern Rock", + L"Comedy", + L"Cult", + L"Gangsta", + L"Top 40", + L"Christian Rap", + L"Pop/Funk", + L"Jungle", + L"Native American", + L"Cabaret", + L"New Wave", + L"Psychedelic", + L"Rave", + L"Showtunes", + L"Trailer", + L"Lo-Fi", + L"Tribal", + L"Acid Punk", + L"Acid Jazz", + L"Polka", + L"Retro", + L"Musical", + L"Rock & Roll", + L"Hard Rock", + L"Folk", + L"Folk/Rock", + L"National Folk", + L"Swing", + L"Fusion", + L"Bebob", + L"Latin", + L"Revival", + L"Celtic", + L"Bluegrass", + L"Avantgarde", + L"Gothic Rock", + L"Progressive Rock", + L"Psychedelic Rock", + L"Symphonic Rock", + L"Slow Rock", + L"Big Band", + L"Chorus", + L"Easy Listening", + L"Acoustic", + L"Humour", + L"Speech", + L"Chanson", + L"Opera", + L"Chamber Music", + L"Sonata", + L"Symphony", + L"Booty Bass", + L"Primus", + L"Porn Groove", + L"Satire", + L"Slow Jam", + L"Club", + L"Tango", + L"Samba", + L"Folklore", + L"Ballad", + L"Power Ballad", + L"Rhythmic Soul", + L"Freestyle", + L"Duet", + L"Punk Rock", + L"Drum Solo", + L"A Cappella", + L"Euro-House", + L"Dance Hall", + L"Goa", + L"Drum & Bass", + L"Club-House", + L"Hardcore", + L"Terror", + L"Indie", + L"BritPop", + L"Negerpunk", + L"Polsk Punk", + L"Beat", + L"Christian Gangsta Rap", + L"Heavy Metal", + L"Black Metal", + L"Crossover", + L"Contemporary Christian", + L"Christian Rock", + L"Merengue", + L"Salsa", + L"Thrash Metal", + L"Anime", + L"Jpop", + L"Synthpop", + L"Abstract", + L"Art Rock", + L"Baroque", + L"Bhangra", + L"Big Beat", + L"Breakbeat", + L"Chillout", + L"Downtempo", + L"Dub", + L"EBM", + L"Eclectic", + L"Electro", + L"Electroclash", + L"Emo", + L"Experimental", + L"Garage", + L"Global", + L"IDM", + L"Illbient", + L"Industro-Goth", + L"Jam Band", + L"Krautrock", + L"Leftfield", + L"Lounge", + L"Math Rock", + L"New Romantic", + L"Nu-Breakz", + L"Post-Punk", + L"Post-Rock", + L"Psytrance", + L"Shoegaze", + L"Space Rock", + L"Trop Rock", + L"World Music", + L"Neoclassical", + L"Audiobook", + L"Audio Theatre", + L"Neue Deutsche Welle", + L"Podcast", + L"Indie Rock", + L"G-Funk", + L"Dubstep", + L"Garage Rock", + L"Psybient" + }; + const int genresSize = sizeof(genres) / sizeof(genres[0]); } StringList ID3v1::genreList() { - static StringList l; - if(l.isEmpty()) { - for(int i = 0; i < genresSize; i++) - l.append(genres[i]); + StringList l; + for(int i = 0; i < genresSize; i++) { + l.append(genres[i]); } + return l; } ID3v1::GenreMap ID3v1::genreMap() { - static GenreMap m; - if(m.isEmpty()) { - for(int i = 0; i < genresSize; i++) - m.insert(genres[i], i); + 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 genres[i] + String::null; // always make a copy - return String::null; + return String(genres[i]); // always make a copy + else + return String(); } int ID3v1::genreIndex(const String &name) { - if(genreMap().contains(name)) - return genreMap()[name]; + for(int i = 0; i < genresSize; ++i) { + if(name == genres[i]) + return i; + } + return 255; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -32,10 +32,20 @@ using namespace TagLib; using namespace ID3v1; +namespace +{ + const ID3v1::StringHandler defaultStringHandler; + const ID3v1::StringHandler *stringHandler = &defaultStringHandler; +} + class ID3v1::Tag::TagPrivate { public: - TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {} + TagPrivate() : + file(0), + tagOffset(0), + track(0), + genre(255) {} File *file; long tagOffset; @@ -45,15 +55,10 @@ String album; String year; String comment; - uchar track; - uchar genre; - - static const StringHandler *stringHandler; + unsigned char track; + unsigned char genre; }; -static const StringHandler defaultStringHandler; -const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler; - //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// @@ -69,26 +74,26 @@ ByteVector ID3v1::StringHandler::render(const String &s) const { - if(!s.isLatin1()) - { + if(s.isLatin1()) + return s.data(String::Latin1); + else return ByteVector(); - } - - return s.data(String::Latin1); } //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// -ID3v1::Tag::Tag() : TagLib::Tag() +ID3v1::Tag::Tag() : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; } -ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag() +ID3v1::Tag::Tag(File *file, long tagOffset) : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; d->file = file; d->tagOffset = tagOffset; @@ -105,11 +110,11 @@ ByteVector data; data.append(fileIdentifier()); - data.append(TagPrivate::stringHandler->render(d->title).resize(30)); - data.append(TagPrivate::stringHandler->render(d->artist).resize(30)); - data.append(TagPrivate::stringHandler->render(d->album).resize(30)); - data.append(TagPrivate::stringHandler->render(d->year).resize(4)); - data.append(TagPrivate::stringHandler->render(d->comment).resize(28)); + data.append(stringHandler->render(d->title).resize(30)); + data.append(stringHandler->render(d->artist).resize(30)); + data.append(stringHandler->render(d->album).resize(30)); + data.append(stringHandler->render(d->year).resize(4)); + data.append(stringHandler->render(d->comment).resize(28)); data.append(char(0)); data.append(char(d->track)); data.append(char(d->genre)); @@ -147,12 +152,12 @@ return ID3v1::genre(d->genre); } -TagLib::uint ID3v1::Tag::year() const +unsigned int ID3v1::Tag::year() const { return d->year.toInt(); } -TagLib::uint ID3v1::Tag::track() const +unsigned int ID3v1::Tag::track() const { return d->track; } @@ -182,32 +187,32 @@ d->genre = ID3v1::genreIndex(s); } -void ID3v1::Tag::setYear(TagLib::uint i) +void ID3v1::Tag::setYear(unsigned int i) { - d->year = i > 0 ? String::number(i) : String::null; + d->year = i > 0 ? String::number(i) : String(); } -void ID3v1::Tag::setTrack(TagLib::uint i) +void ID3v1::Tag::setTrack(unsigned int i) { d->track = i < 256 ? i : 0; } -TagLib::uint ID3v1::Tag::genreNumber() const +unsigned int ID3v1::Tag::genreNumber() const { return d->genre; } -void ID3v1::Tag::setGenreNumber(TagLib::uint i) +void ID3v1::Tag::setGenreNumber(unsigned int i) { d->genre = i < 256 ? i : 255; } void ID3v1::Tag::setStringHandler(const StringHandler *handler) { - if (handler) - TagPrivate::stringHandler = handler; + if(handler) + stringHandler = handler; else - TagPrivate::stringHandler = &defaultStringHandler; + stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// @@ -219,7 +224,7 @@ if(d->file && d->file->isValid()) { d->file->seek(d->tagOffset); // read the tag -- always 128 bytes - ByteVector data = d->file->readBlock(128); + const ByteVector data = d->file->readBlock(128); // some initial sanity checking if(data.size() == 128 && data.startsWith("TAG")) @@ -233,16 +238,16 @@ { int offset = 3; - d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + d->title = stringHandler->parse(data.mid(offset, 30)); offset += 30; - d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + d->artist = stringHandler->parse(data.mid(offset, 30)); offset += 30; - d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + d->album = stringHandler->parse(data.mid(offset, 30)); offset += 30; - d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4)); + d->year = stringHandler->parse(data.mid(offset, 4)); offset += 4; // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this @@ -253,13 +258,13 @@ if(data[offset + 28] == 0 && data[offset + 29] != 0) { // ID3v1.1 detected - d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28)); - d->track = uchar(data[offset + 29]); + d->comment = stringHandler->parse(data.mid(offset, 28)); + d->track = static_cast(data[offset + 29]); } else d->comment = data.mid(offset, 30); offset += 30; - d->genre = uchar(data[offset]); + d->genre = static_cast(data[offset]); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v1/id3v1tag.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v1/id3v1tag.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v1/id3v1tag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v1/id3v1tag.h 2016-07-19 15:25:23.000000000 +0000 @@ -140,23 +140,23 @@ virtual String album() const; virtual String comment() const; virtual String genre() const; - virtual TagLib::uint year() const; - virtual TagLib::uint track() const; + virtual unsigned int year() const; + virtual unsigned int track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); - virtual void setYear(TagLib::uint i); - virtual void setTrack(TagLib::uint i); + virtual void setYear(unsigned int i); + virtual void setTrack(unsigned int i); /*! * Returns the genre in number. * * \note Normally 255 indicates that this tag contains no genre. */ - TagLib::uint genreNumber() const; + unsigned int genreNumber() const; /*! * Sets the genre in number to \a i. @@ -164,7 +164,7 @@ * \note Valid value is from 0 up to 255. Normally 255 indicates that * this tag contains no genre. */ - void setGenreNumber(TagLib::uint i); + void setGenreNumber(unsigned int i); /*! * Sets the string handler that decides how the ID3v1 data will be diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -137,7 +137,7 @@ d->mimeType = readStringField(data, String::Latin1, &pos); /* Now we need at least two more bytes available */ - if (uint(pos) + 1 >= data.size()) { + if(static_cast(pos) + 1 >= data.size()) { debug("Truncated picture frame."); return; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -44,10 +44,10 @@ const ID3v2::Header *tagHeader; ByteVector elementID; - TagLib::uint startTime; - TagLib::uint endTime; - TagLib::uint startOffset; - TagLib::uint endOffset; + unsigned int startTime; + unsigned int endTime; + unsigned int startOffset; + unsigned int endOffset; FrameListMap embeddedFrameListMap; FrameList embeddedFrameList; }; @@ -65,8 +65,8 @@ } ChapterFrame::ChapterFrame(const ByteVector &elementID, - TagLib::uint startTime, TagLib::uint endTime, - TagLib::uint startOffset, TagLib::uint endOffset, + unsigned int startTime, unsigned int endTime, + unsigned int startOffset, unsigned int endOffset, const FrameList &embeddedFrames) : ID3v2::Frame("CHAP") { @@ -97,22 +97,22 @@ return d->elementID; } -TagLib::uint ChapterFrame::startTime() const +unsigned int ChapterFrame::startTime() const { return d->startTime; } -TagLib::uint ChapterFrame::endTime() const +unsigned int ChapterFrame::endTime() const { return d->endTime; } -TagLib::uint ChapterFrame::startOffset() const +unsigned int ChapterFrame::startOffset() const { return d->startOffset; } -TagLib::uint ChapterFrame::endOffset() const +unsigned int ChapterFrame::endOffset() const { return d->endOffset; } @@ -125,22 +125,22 @@ d->elementID = d->elementID.mid(0, d->elementID.size() - 1); } -void ChapterFrame::setStartTime(const TagLib::uint &sT) +void ChapterFrame::setStartTime(const unsigned int &sT) { d->startTime = sT; } -void ChapterFrame::setEndTime(const TagLib::uint &eT) +void ChapterFrame::setEndTime(const unsigned int &eT) { d->endTime = eT; } -void ChapterFrame::setStartOffset(const TagLib::uint &sO) +void ChapterFrame::setStartOffset(const unsigned int &sO) { d->startOffset = sO; } -void ChapterFrame::setEndOffset(const TagLib::uint &eO) +void ChapterFrame::setEndOffset(const unsigned int &eO) { d->endOffset = eO; } @@ -238,7 +238,7 @@ void ChapterFrame::parseFields(const ByteVector &data) { - TagLib::uint size = data.size(); + unsigned int size = data.size(); if(size < 18) { debug("A CHAP frame must contain at least 18 bytes (1 byte element ID " "terminated by null and 4x4 bytes for start and end time and offset)."); @@ -246,7 +246,7 @@ } int pos = 0; - TagLib::uint embPos = 0; + unsigned int embPos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->startTime = data.toUInt(pos, true); pos += 4; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -62,8 +62,8 @@ * All times are in milliseconds. */ ChapterFrame(const ByteVector &elementID, - uint startTime, uint endTime, - uint startOffset, uint endOffset, + unsigned int startTime, unsigned int endTime, + unsigned int startOffset, unsigned int endOffset, const FrameList &embeddedFrames = FrameList()); /*! @@ -84,14 +84,14 @@ * * \see setStartTime() */ - uint startTime() const; + unsigned int startTime() const; /*! * Returns time of chapter's end (in milliseconds). * * \see setEndTime() */ - uint endTime() const; + unsigned int endTime() const; /*! * Returns zero based byte offset (count of bytes from the beginning @@ -100,7 +100,7 @@ * \note If returned value is 0xFFFFFFFF, start time should be used instead. * \see setStartOffset() */ - uint startOffset() const; + unsigned int startOffset() const; /*! * Returns zero based byte offset (count of bytes from the beginning @@ -109,7 +109,7 @@ * \note If returned value is 0xFFFFFFFF, end time should be used instead. * \see setEndOffset() */ - uint endOffset() const; + unsigned int endOffset() const; /*! * Sets the element ID of the frame to \a eID. If \a eID isn't @@ -124,14 +124,14 @@ * * \see startTime() */ - void setStartTime(const uint &sT); + void setStartTime(const unsigned int &sT); /*! * Sets time of chapter's end (in milliseconds) to \a eT. * * \see endTime() */ - void setEndTime(const uint &eT); + void setEndTime(const unsigned int &eT); /*! * Sets zero based byte offset (count of bytes from the beginning @@ -139,7 +139,7 @@ * * \see startOffset() */ - void setStartOffset(const uint &sO); + void setStartOffset(const unsigned int &sO); /*! * Sets zero based byte offset (count of bytes from the beginning @@ -147,7 +147,7 @@ * * \see endOffset() */ - void setEndOffset(const uint &eO); + void setEndOffset(const unsigned int &eO); /*! * Returns a reference to the frame list map. This is an FrameListMap of diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -116,8 +116,6 @@ PropertyMap map; if(key.isEmpty() || key == "COMMENT") map.insert("COMMENT", text()); - else if(key.isNull()) - map.unsupportedData().append(L"COMM/" + description()); else map.insert("COMMENT:" + key, text()); return map; @@ -164,7 +162,7 @@ } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); - } + } } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -109,8 +109,8 @@ int pos = 1; d->synchedEvents.clear(); while(pos + 4 < end) { - EventType type = EventType(uchar(data[pos++])); - uint time = data.toUInt(pos, true); + EventType type = static_cast(static_cast(data[pos++])); + unsigned int time = data.toUInt(pos, true); pos += 4; d->synchedEvents.append(SynchedEvent(time, type)); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -108,8 +108,8 @@ * Single entry of time stamp and event. */ struct SynchedEvent { - SynchedEvent(uint ms, EventType t) : time(ms), type(t) {} - uint time; + SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {} + unsigned int time; EventType type; }; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -1,6 +1,7 @@ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org + copyright : (C) 2006 by Aaron VonderHaar email : avh4@users.sourceforge.net ***************************************************************************/ @@ -26,6 +27,7 @@ ***************************************************************************/ #include +#include #include "generalencapsulatedobjectframe.h" @@ -151,15 +153,21 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const { + StringList sl; + sl.append(d->fileName); + sl.append(d->description); + + const String::Type encoding = checkTextEncoding(sl, d->textEncoding); + ByteVector data; - data.append(char(d->textEncoding)); + data.append(char(encoding)); data.append(d->mimeType.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); - data.append(d->fileName.data(d->textEncoding)); - data.append(textDelimiter(d->textEncoding)); - data.append(d->description.data(d->textEncoding)); - data.append(textDelimiter(d->textEncoding)); + data.append(d->fileName.data(encoding)); + data.append(textDelimiter(encoding)); + data.append(d->description.data(encoding)); + data.append(textDelimiter(encoding)); data.append(d->data); return data; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -1,6 +1,7 @@ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org + copyright : (C) 2006 by Aaron VonderHaar email : avh4@users.sourceforge.net ***************************************************************************/ diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -24,9 +24,10 @@ ***************************************************************************/ #include +#include +#include #include "ownershipframe.h" -#include using namespace TagLib; using namespace ID3v2; @@ -113,24 +114,24 @@ void OwnershipFrame::parseFields(const ByteVector &data) { int pos = 0; - + // Get the text encoding d->textEncoding = String::Type(data[0]); pos += 1; - + // Read the price paid this is a null terminate string d->pricePaid = readStringField(data, String::Latin1, &pos); - + // If we don't have at least 8 bytes left then don't parse the rest of the // data if(data.size() - pos < 8) { return; } - + // Read the date purchased YYYYMMDD d->datePurchased = String(data.mid(pos, 8)); pos += 8; - + // Read the seller if(d->textEncoding == String::Latin1) d->seller = Tag::latin1StringHandler()->parse(data.mid(pos)); @@ -140,14 +141,19 @@ ByteVector OwnershipFrame::renderFields() const { + StringList sl; + sl.append(d->seller); + + const String::Type encoding = checkTextEncoding(sl, d->textEncoding); + ByteVector v; - - v.append(char(d->textEncoding)); + + v.append(char(encoding)); v.append(d->pricePaid.data(String::Latin1)); v.append(textDelimiter(String::Latin1)); v.append(d->datePurchased.data(String::Latin1)); - v.append(d->seller.data(d->textEncoding)); - + v.append(d->seller.data(encoding)); + return v; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,79 @@ +/*************************************************************************** + copyright : (C) 2015 by Urs Fleisch + email : ufleisch@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#include "podcastframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class PodcastFrame::PodcastFramePrivate +{ +public: + ByteVector fieldData; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +PodcastFrame::PodcastFrame() : Frame("PCST") +{ + d = new PodcastFramePrivate; + d->fieldData = ByteVector(4, '\0'); +} + +PodcastFrame::~PodcastFrame() +{ + delete d; +} + +String PodcastFrame::toString() const +{ + return String(); +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void PodcastFrame::parseFields(const ByteVector &data) +{ + d->fieldData = data; +} + +ByteVector PodcastFrame::renderFields() const +{ + return d->fieldData; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new PodcastFramePrivate; + parseFields(fieldData(data)); +} diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,80 @@ +/*************************************************************************** + copyright : (C) 2015 by Urs Fleisch + email : ufleisch@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_PODCASTFRAME_H +#define TAGLIB_PODCASTFRAME_H + +#include "id3v2frame.h" +#include "taglib_export.h" + +namespace TagLib { + + namespace ID3v2 { + + //! ID3v2 podcast frame + /*! + * An implementation of ID3v2 podcast flag, a frame with four zero bytes. + */ + class TAGLIB_EXPORT PodcastFrame : public Frame + { + friend class FrameFactory; + + public: + /*! + * Construct a podcast frame. + */ + PodcastFrame(); + + /*! + * Destroys this PodcastFrame instance. + */ + virtual ~PodcastFrame(); + + /*! + * Returns a null string. + */ + virtual String toString() const; + + protected: + // Reimplementations. + + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + private: + /*! + * The constructor used by the FrameFactory. + */ + PodcastFrame(const ByteVector &data, Header *h); + PodcastFrame(const PodcastFrame &); + PodcastFrame &operator=(const PodcastFrame &); + + class PodcastFramePrivate; + PodcastFramePrivate *d; + }; + + } +} +#endif diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -36,7 +36,7 @@ PopularimeterFramePrivate() : rating(0), counter(0) {} String email; int rating; - TagLib::uint counter; + unsigned int counter; }; //////////////////////////////////////////////////////////////////////////////// @@ -84,12 +84,12 @@ d->rating = s; } -TagLib::uint PopularimeterFrame::counter() const +unsigned int PopularimeterFrame::counter() const { return d->counter; } -void PopularimeterFrame::setCounter(TagLib::uint s) +void PopularimeterFrame::setCounter(unsigned int s) { d->counter = s; } @@ -109,7 +109,7 @@ if(pos < size) { d->rating = (unsigned char)(data[pos++]); if(pos < size) { - d->counter = data.toUInt(static_cast(pos)); + d->counter = data.toUInt(static_cast(pos)); } } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -100,14 +100,14 @@ * * \see setCounter() */ - uint counter() const; + unsigned int counter() const; /*! * Set the counter. * * \see counter() */ - void setCounter(uint counter); + void setCounter(unsigned int counter); protected: // Reimplementations. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -31,11 +31,6 @@ using namespace TagLib; using namespace ID3v2; -static inline int bitsToBytes(int i) -{ - return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1; -} - struct ChannelData { ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} @@ -185,19 +180,18 @@ while(pos <= (int)data.size() - 4) { - ChannelType type = ChannelType(data[pos]); pos += 1; ChannelData &channel = d->channels[type]; - channel.volumeAdjustment = data.toShort(static_cast(pos)); + channel.volumeAdjustment = data.toShort(static_cast(pos)); pos += 2; channel.peakVolume.bitsRepresentingPeak = data[pos]; pos += 1; - int bytes = bitsToBytes(channel.peakVolume.bitsRepresentingPeak); + const int bytes = (channel.peakVolume.bitsRepresentingPeak + 7) / 8; channel.peakVolume.peakVolume = data.mid(pos, bytes); pos += bytes; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -117,8 +117,7 @@ d->language = languageEncoding.mid(0, 3); } -void SynchronizedLyricsFrame::setTimestampFormat( - SynchronizedLyricsFrame::TimestampFormat f) +void SynchronizedLyricsFrame::setTimestampFormat(SynchronizedLyricsFrame::TimestampFormat f) { d->timestampFormat = f; } @@ -159,7 +158,7 @@ int pos = 6; d->description = readStringField(data, d->textEncoding, &pos); - if(d->description.isNull()) + if(pos == 6) return; /* @@ -171,7 +170,7 @@ */ String::Type encWithEndianness = d->textEncoding; if(d->textEncoding == String::UTF16) { - ushort bom = data.toUShort(6, true); + unsigned short bom = data.toUShort(6, true); if(bom == 0xfffe) { encWithEndianness = String::UTF16LE; } else if(bom == 0xfeff) { @@ -184,16 +183,16 @@ String::Type enc = d->textEncoding; // If a UTF16 string has no BOM, use the encoding found above. if(enc == String::UTF16 && pos + 1 < end) { - ushort bom = data.toUShort(pos, true); + unsigned short bom = data.toUShort(pos, true); if(bom != 0xfffe && bom != 0xfeff) { enc = encWithEndianness; } } String text = readStringField(data, enc, &pos); - if(text.isNull() || pos + 4 > end) + if(text.isEmpty() || pos + 4 > end) return; - uint time = data.toUInt(pos, true); + unsigned int time = data.toUInt(pos, true); pos += 4; d->synchedText.append(SynchedText(time, text)); diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -85,8 +85,8 @@ * Single entry of time stamp and lyrics text. */ struct SynchedText { - SynchedText(uint ms, String str) : time(ms), text(str) {} - uint time; + SynchedText(unsigned int ms, String str) : time(ms), text(str) {} + unsigned int time; String text; }; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -121,7 +121,7 @@ return d->isOrdered; } -TagLib::uint TableOfContentsFrame::entryCount() const +unsigned int TableOfContentsFrame::entryCount() const { return d->childElements.size(); } @@ -214,7 +214,7 @@ String TableOfContentsFrame::toString() const { - return String::null; + return String(); } PropertyMap TableOfContentsFrame::asProperties() const @@ -261,7 +261,7 @@ void TableOfContentsFrame::parseFields(const ByteVector &data) { - TagLib::uint size = data.size(); + unsigned int size = data.size(); if(size < 6) { debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by " "null, 1 byte flags, 1 byte entry count and 1 byte child element ID terminated " @@ -270,12 +270,12 @@ } int pos = 0; - TagLib::uint embPos = 0; + unsigned int embPos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->isTopLevel = (data.at(pos) & 2) > 0; d->isOrdered = (data.at(pos++) & 1) > 0; - TagLib::uint entryCount = data.at(pos++); - for(TagLib::uint i = 0; i < entryCount; i++) { + unsigned int entryCount = data.at(pos++); + for(unsigned int i = 0; i < entryCount; i++) { ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->childElements.append(childElementID); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -95,7 +95,7 @@ * * \see childElements() */ - uint entryCount() const; + unsigned int entryCount() const; /*! * Returns list of child elements of the frame. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -119,22 +119,26 @@ d->textEncoding = encoding; } -// array of allowed TIPL prefixes and their corresponding key value -static const TagLib::uint involvedPeopleSize = 5; -static const char* involvedPeople[][2] = { - {"ARRANGER", "ARRANGER"}, - {"ENGINEER", "ENGINEER"}, - {"PRODUCER", "PRODUCER"}, - {"DJ-MIX", "DJMIXER"}, - {"MIX", "MIXER"}, -}; +namespace +{ + // array of allowed TIPL prefixes and their corresponding key value + const char* involvedPeople[][2] = { + {"ARRANGER", "ARRANGER"}, + {"ENGINEER", "ENGINEER"}, + {"PRODUCER", "PRODUCER"}, + {"DJ-MIX", "DJMIXER"}, + {"MIX", "MIXER"}, + }; + const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]); +} const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static { static KeyConversionMap m; - if(m.isEmpty()) - for(uint i = 0; i < involvedPeopleSize; ++i) + if(m.isEmpty()) { + for(size_t i = 0; i < involvedPeopleSize; ++i) m.insert(involvedPeople[i][1], involvedPeople[i][0]); + } return m; } @@ -146,7 +150,7 @@ return makeTMCLProperties(); PropertyMap map; String tagName = frameIDToKey(frameID()); - if(tagName.isNull()) { + if(tagName.isEmpty()) { map.unsupportedData().append(frameID()); return map; } @@ -265,7 +269,7 @@ StringList l = fieldList(); for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { bool found = false; - for(uint i = 0; i < involvedPeopleSize; ++i) + for(size_t i = 0; i < involvedPeopleSize; ++i) if(*it == involvedPeople[i][0]) { map.insert(involvedPeople[i][1], (++it)->split(",")); found = true; @@ -292,7 +296,7 @@ StringList l = fieldList(); for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { String instrument = it->upper(); - if(instrument.isNull()) { + if(instrument.isEmpty()) { // instrument is not a valid key -> frame unsupported map.clear(); map.unsupportedData().append(frameID()); @@ -312,8 +316,8 @@ d(0) { StringList l; - l.append(String::null); - l.append(String::null); + l.append(String()); + l.append(String()); setText(l); } @@ -341,7 +345,7 @@ { return !TextIdentificationFrame::fieldList().isEmpty() ? TextIdentificationFrame::fieldList().front() - : String::null; + : String(); } StringList UserTextIdentificationFrame::fieldList() const @@ -354,7 +358,7 @@ void UserTextIdentificationFrame::setText(const String &text) { if(description().isEmpty()) - setDescription(String::null); + setDescription(String()); TextIdentificationFrame::setText(StringList(description()).append(text)); } @@ -362,7 +366,7 @@ void UserTextIdentificationFrame::setText(const StringList &fields) { if(description().isEmpty()) - setDescription(String::null); + setDescription(String()); TextIdentificationFrame::setText(StringList(description()).append(fields)); } @@ -417,7 +421,7 @@ int fields = fieldList().size(); if(fields == 0) - setDescription(String::null); + setDescription(String()); if(fields <= 1) - setText(String::null); + setText(String()); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -86,7 +86,7 @@ String UniqueFileIdentifierFrame::toString() const { - return String::null; + return String(); } PropertyMap UniqueFileIdentifierFrame::asProperties() const diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -51,7 +51,7 @@ String UnknownFrame::toString() const { - return String::null; + return String(); } ByteVector UnknownFrame::data() const diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -1,6 +1,7 @@ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org + copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ @@ -119,8 +120,6 @@ String key = description().upper(); if(key.isEmpty() || key.upper() == "LYRICS") map.insert("LYRICS", text()); - else if(key.isNull()) - map.unsupportedData().append(L"USLT/" + description()); else map.insert("LYRICS:" + key, text()); return map; @@ -164,19 +163,25 @@ } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); - } + } } } ByteVector UnsynchronizedLyricsFrame::renderFields() const { + StringList sl; + sl.append(d->description); + sl.append(d->text); + + const String::Type encoding = checkTextEncoding(sl, d->textEncoding); + ByteVector v; - v.append(char(d->textEncoding)); + v.append(char(encoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); - v.append(d->description.data(d->textEncoding)); - v.append(textDelimiter(d->textEncoding)); - v.append(d->text.data(d->textEncoding)); + v.append(d->description.data(encoding)); + v.append(textDelimiter(encoding)); + v.append(d->text.data(encoding)); return v; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -1,6 +1,7 @@ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org + copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ @@ -84,7 +85,7 @@ { String key = frameIDToKey(frameID()); PropertyMap map; - if(key.isNull()) + if(key.isEmpty()) // unknown W*** frame - this normally shouldn't happen map.unsupportedData().append(frameID()); else @@ -159,8 +160,6 @@ String key = description().upper(); if(key.isEmpty() || key.upper() == "URL") map.insert("URL", url()); - else if(key.isNull()) - map.unsupportedData().append(L"WXXX/" + description()); else map.insert("URL:" + key, url()); return map; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h 2016-07-19 15:25:23.000000000 +0000 @@ -1,6 +1,7 @@ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org + copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -34,7 +34,7 @@ public: ExtendedHeaderPrivate() : size(0) {} - uint size; + unsigned int size; }; //////////////////////////////////////////////////////////////////////////////// @@ -51,7 +51,7 @@ delete d; } -TagLib::uint ExtendedHeader::size() const +unsigned int ExtendedHeader::size() const { return d->size; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h 2016-07-19 15:25:23.000000000 +0000 @@ -62,7 +62,7 @@ * Returns the size of the extended header. This is variable for the * extended header. */ - uint size() const; + unsigned int size() const; /*! * Sets the data that will be used as the extended header. Since the diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2footer.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2footer.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2footer.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2footer.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -31,30 +31,27 @@ class Footer::FooterPrivate { -public: - static const uint size = 10; }; -Footer::Footer() +Footer::Footer() : + d(0) { - } Footer::~Footer() { - } -TagLib::uint Footer::size() +unsigned int Footer::size() { - return FooterPrivate::size; + return 10; } ByteVector Footer::render(const Header *header) const { - ByteVector headerData = header->render(); - headerData[0] = '3'; - headerData[1] = 'D'; - headerData[2] = 'I'; - return headerData; + ByteVector headerData = header->render(); + headerData[0] = '3'; + headerData[1] = 'D'; + headerData[2] = 'I'; + return headerData; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2footer.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2footer.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2footer.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2footer.h 2016-07-19 15:25:23.000000000 +0000 @@ -62,7 +62,7 @@ /*! * Returns the size of the footer. Presently this is always 10 bytes. */ - static uint size(); + static unsigned int size(); /*! * Renders the footer based on the data in \a header. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,22 +23,16 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - -#if HAVE_ZLIB -#include -#endif - #include #include #include +#include #include "id3v2tag.h" #include "id3v2frame.h" #include "id3v2synchdata.h" + #include "tpropertymap.h" #include "frames/textidentificationframe.h" #include "frames/urllinkframe.h" @@ -85,22 +79,22 @@ // static methods //////////////////////////////////////////////////////////////////////////////// -TagLib::uint Frame::headerSize() +unsigned int Frame::headerSize() { return Header::size(); } -TagLib::uint Frame::headerSize(uint version) +unsigned int Frame::headerSize(unsigned int version) { return Header::size(version); } ByteVector Frame::textDelimiter(String::Type t) { - ByteVector d = char(0); if(t == String::UTF16 || t == String::UTF16BE || t == String::UTF16LE) - d.append(char(0)); - return d; + return ByteVector(2, '\0'); + else + return ByteVector(1, '\0'); } const String Frame::instrumentPrefix("PERFORMER:"); @@ -116,8 +110,9 @@ { // check if the key is contained in the key<=>frameID mapping ByteVector frameID = keyToFrameID(key); - if(!frameID.isNull()) { - if(frameID[0] == 'T'){ // text frame + if(!frameID.isEmpty()) { + // Apple proprietary WFED (Podcast URL) is in fact a text frame. + if(frameID[0] == 'T' || frameID == "WFED"){ // text frame TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8); frame->setText(values); return frame; @@ -169,10 +164,10 @@ if(d->header) return d->header->frameID(); else - return ByteVector::null; + return ByteVector(); } -TagLib::uint Frame::size() const +unsigned int Frame::size() const { if(d->header) return d->header->frameSize(); @@ -240,68 +235,31 @@ ByteVector Frame::fieldData(const ByteVector &frameData) const { - uint headerSize = Header::size(d->header->version()); + unsigned int headerSize = Header::size(d->header->version()); - uint frameDataOffset = headerSize; - uint frameDataLength = size(); + unsigned int frameDataOffset = headerSize; + unsigned int frameDataLength = size(); if(d->header->compression() || d->header->dataLengthIndicator()) { frameDataLength = SynchData::toUInt(frameData.mid(headerSize, 4)); frameDataOffset += 4; } -#if HAVE_ZLIB - if(d->header->compression() && - !d->header->encryption()) - { + if(zlib::isAvailable() && d->header->compression() && !d->header->encryption()) { if(frameData.size() <= frameDataOffset) { debug("Compressed frame doesn't have enough data to decode"); return ByteVector(); } - z_stream stream = {}; - - if(inflateInit(&stream) != Z_OK) - return ByteVector(); - - stream.avail_in = (uLongf) frameData.size() - frameDataOffset; - stream.next_in = (Bytef *) frameData.data() + frameDataOffset; - - static const uint chunkSize = 1024; - - ByteVector data; - ByteVector chunk(chunkSize); - - do { - stream.avail_out = (uLongf) chunk.size(); - stream.next_out = (Bytef *) chunk.data(); - - int result = inflate(&stream, Z_NO_FLUSH); - - if(result == Z_STREAM_ERROR || - result == Z_NEED_DICT || - result == Z_DATA_ERROR || - result == Z_MEM_ERROR) - { - if(result != Z_STREAM_ERROR) - inflateEnd(&stream); - debug("Error reading compressed stream"); - return ByteVector(); - } - - data.append(stream.avail_out == 0 ? chunk : chunk.mid(0, chunk.size() - stream.avail_out)); - } while(stream.avail_out == 0); - - inflateEnd(&stream); - - if(frameDataLength != data.size()) + const ByteVector outData = zlib::decompress(frameData.mid(frameDataOffset)); + if(!outData.isEmpty() && frameDataLength != outData.size()) { debug("frameDataLength does not match the data length returned by zlib"); + } - return data; + return outData; } - else -#endif - return frameData.mid(frameDataOffset, frameDataLength); + + return frameData.mid(frameDataOffset, frameDataLength); } String Frame::readStringField(const ByteVector &data, String::Type encoding, int *position) @@ -316,7 +274,7 @@ int end = data.find(delimiter, *position, delimiter.size()); if(end < *position) - return String::null; + return String(); String str; if(encoding == String::Latin1) @@ -334,7 +292,7 @@ return checkEncoding(fields, encoding, 4); } -String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding, uint version) // static +String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding, unsigned int version) // static { if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4) return String::UTF16; @@ -363,161 +321,145 @@ return checkEncoding(fields, encoding, header()->version()); } -static const TagLib::uint frameTranslationSize = 51; -static const char *frameTranslation[][2] = { - // Text information frames - { "TALB", "ALBUM"}, - { "TBPM", "BPM" }, - { "TCOM", "COMPOSER" }, - { "TCON", "GENRE" }, - { "TCOP", "COPYRIGHT" }, - { "TDEN", "ENCODINGTIME" }, - { "TDLY", "PLAYLISTDELAY" }, - { "TDOR", "ORIGINALDATE" }, - { "TDRC", "DATE" }, - // { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - { "TDRL", "RELEASEDATE" }, - { "TDTG", "TAGGINGDATE" }, - { "TENC", "ENCODEDBY" }, - { "TEXT", "LYRICIST" }, - { "TFLT", "FILETYPE" }, - //{ "TIPL", "INVOLVEDPEOPLE" }, handled separately - { "TIT1", "CONTENTGROUP" }, - { "TIT2", "TITLE"}, - { "TIT3", "SUBTITLE" }, - { "TKEY", "INITIALKEY" }, - { "TLAN", "LANGUAGE" }, - { "TLEN", "LENGTH" }, - //{ "TMCL", "MUSICIANCREDITS" }, handled separately - { "TMED", "MEDIA" }, - { "TMOO", "MOOD" }, - { "TOAL", "ORIGINALALBUM" }, - { "TOFN", "ORIGINALFILENAME" }, - { "TOLY", "ORIGINALLYRICIST" }, - { "TOPE", "ORIGINALARTIST" }, - { "TOWN", "OWNER" }, - { "TPE1", "ARTIST"}, - { "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST' - { "TPE3", "CONDUCTOR" }, - { "TPE4", "REMIXER" }, // could also be ARRANGER - { "TPOS", "DISCNUMBER" }, - { "TPRO", "PRODUCEDNOTICE" }, - { "TPUB", "LABEL" }, - { "TRCK", "TRACKNUMBER" }, - { "TRSN", "RADIOSTATION" }, - { "TRSO", "RADIOSTATIONOWNER" }, - { "TSOA", "ALBUMSORT" }, - { "TSOP", "ARTISTSORT" }, - { "TSOT", "TITLESORT" }, - { "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes - { "TSRC", "ISRC" }, - { "TSSE", "ENCODING" }, - // URL frames - { "WCOP", "COPYRIGHTURL" }, - { "WOAF", "FILEWEBPAGE" }, - { "WOAR", "ARTISTWEBPAGE" }, - { "WOAS", "AUDIOSOURCEWEBPAGE" }, - { "WORS", "RADIOSTATIONWEBPAGE" }, - { "WPAY", "PAYMENTWEBPAGE" }, - { "WPUB", "PUBLISHERWEBPAGE" }, - //{ "WXXX", "URL"}, handled specially - // Other frames - { "COMM", "COMMENT" }, - //{ "USLT", "LYRICS" }, handled specially -}; - -static const TagLib::uint txxxFrameTranslationSize = 8; -static const char *txxxFrameTranslation[][2] = { - { "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, - { "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, - { "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, - { "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, - { "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, - { "Acoustid Id", "ACOUSTID_ID" }, - { "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" }, - { "MusicIP PUID", "MUSICIP_PUID" }, -}; - -Map &idMap() +namespace { - static Map m; - if(m.isEmpty()) - for(size_t i = 0; i < frameTranslationSize; ++i) - m[frameTranslation[i][0]] = frameTranslation[i][1]; - return m; + const char *frameTranslation[][2] = { + // Text information frames + { "TALB", "ALBUM"}, + { "TBPM", "BPM" }, + { "TCOM", "COMPOSER" }, + { "TCON", "GENRE" }, + { "TCOP", "COPYRIGHT" }, + { "TDEN", "ENCODINGTIME" }, + { "TDLY", "PLAYLISTDELAY" }, + { "TDOR", "ORIGINALDATE" }, + { "TDRC", "DATE" }, + // { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + // { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + // { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + // { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + { "TDRL", "RELEASEDATE" }, + { "TDTG", "TAGGINGDATE" }, + { "TENC", "ENCODEDBY" }, + { "TEXT", "LYRICIST" }, + { "TFLT", "FILETYPE" }, + //{ "TIPL", "INVOLVEDPEOPLE" }, handled separately + { "TIT1", "CONTENTGROUP" }, + { "TIT2", "TITLE"}, + { "TIT3", "SUBTITLE" }, + { "TKEY", "INITIALKEY" }, + { "TLAN", "LANGUAGE" }, + { "TLEN", "LENGTH" }, + //{ "TMCL", "MUSICIANCREDITS" }, handled separately + { "TMED", "MEDIA" }, + { "TMOO", "MOOD" }, + { "TOAL", "ORIGINALALBUM" }, + { "TOFN", "ORIGINALFILENAME" }, + { "TOLY", "ORIGINALLYRICIST" }, + { "TOPE", "ORIGINALARTIST" }, + { "TOWN", "OWNER" }, + { "TPE1", "ARTIST"}, + { "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST' + { "TPE3", "CONDUCTOR" }, + { "TPE4", "REMIXER" }, // could also be ARRANGER + { "TPOS", "DISCNUMBER" }, + { "TPRO", "PRODUCEDNOTICE" }, + { "TPUB", "LABEL" }, + { "TRCK", "TRACKNUMBER" }, + { "TRSN", "RADIOSTATION" }, + { "TRSO", "RADIOSTATIONOWNER" }, + { "TSOA", "ALBUMSORT" }, + { "TSOP", "ARTISTSORT" }, + { "TSOT", "TITLESORT" }, + { "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes + { "TSRC", "ISRC" }, + { "TSSE", "ENCODING" }, + // URL frames + { "WCOP", "COPYRIGHTURL" }, + { "WOAF", "FILEWEBPAGE" }, + { "WOAR", "ARTISTWEBPAGE" }, + { "WOAS", "AUDIOSOURCEWEBPAGE" }, + { "WORS", "RADIOSTATIONWEBPAGE" }, + { "WPAY", "PAYMENTWEBPAGE" }, + { "WPUB", "PUBLISHERWEBPAGE" }, + //{ "WXXX", "URL"}, handled specially + // Other frames + { "COMM", "COMMENT" }, + //{ "USLT", "LYRICS" }, handled specially + // Apple iTunes proprietary frames + { "PCST", "PODCAST" }, + { "TCAT", "PODCASTCATEGORY" }, + { "TDES", "PODCASTDESC" }, + { "TGID", "PODCASTID" }, + { "WFED", "PODCASTURL" }, + }; + const size_t frameTranslationSize = sizeof(frameTranslation) / sizeof(frameTranslation[0]); + + const char *txxxFrameTranslation[][2] = { + { "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID" }, + { "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ_ARTISTID" }, + { "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ_ALBUMARTISTID" }, + { "MUSICBRAINZ RELEASE GROUP ID", "MUSICBRAINZ_RELEASEGROUPID" }, + { "MUSICBRAINZ WORK ID", "MUSICBRAINZ_WORKID" }, + { "ACOUSTID ID", "ACOUSTID_ID" }, + { "ACOUSTID FINGERPRINT", "ACOUSTID_FINGERPRINT" }, + { "MUSICIP PUID", "MUSICIP_PUID" }, + }; + const size_t txxxFrameTranslationSize = sizeof(txxxFrameTranslation) / sizeof(txxxFrameTranslation[0]); + + // list of deprecated frames and their successors + const char *deprecatedFrames[][2] = { + {"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3) + {"TDAT", "TDRC"}, // 2.3 -> 2.4 + {"TYER", "TDRC"}, // 2.3 -> 2.4 + {"TIME", "TDRC"}, // 2.3 -> 2.4 + }; + const size_t deprecatedFramesSize = sizeof(deprecatedFrames) / sizeof(deprecatedFrames[0]);; } -Map &txxxMap() +String Frame::frameIDToKey(const ByteVector &id) { - static Map m; - if(m.isEmpty()) { - for(size_t i = 0; i < txxxFrameTranslationSize; ++i) { - String key = String(txxxFrameTranslation[i][0]).upper(); - m[key] = txxxFrameTranslation[i][1]; + ByteVector id24 = id; + for(size_t i = 0; i < deprecatedFramesSize; ++i) { + if(id24 == deprecatedFrames[i][0]) { + id24 = deprecatedFrames[i][1]; + break; } } - return m; -} - -// list of deprecated frames and their successors -static const TagLib::uint deprecatedFramesSize = 4; -static const char *deprecatedFrames[][2] = { - {"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3) - {"TDAT", "TDRC"}, // 2.3 -> 2.4 - {"TYER", "TDRC"}, // 2.3 -> 2.4 - {"TIME", "TDRC"}, // 2.3 -> 2.4 -}; - -Map &deprecationMap() -{ - static Map depMap; - if(depMap.isEmpty()) - for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i) - depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1]; - return depMap; -} - -String Frame::frameIDToKey(const ByteVector &id) -{ - Map &m = idMap(); - if(m.contains(id)) - return m[id]; - if(deprecationMap().contains(id)) - return m[deprecationMap()[id]]; - return String::null; + for(size_t i = 0; i < frameTranslationSize; ++i) { + if(id24 == frameTranslation[i][0]) + return frameTranslation[i][1]; + } + return String(); } ByteVector Frame::keyToFrameID(const String &s) { - static Map m; - if(m.isEmpty()) - for(size_t i = 0; i < frameTranslationSize; ++i) - m[frameTranslation[i][1]] = frameTranslation[i][0]; - if(m.contains(s.upper())) - return m[s]; - return ByteVector::null; + const String key = s.upper(); + for(size_t i = 0; i < frameTranslationSize; ++i) { + if(key == frameTranslation[i][1]) + return frameTranslation[i][0]; + } + return ByteVector(); } String Frame::txxxToKey(const String &description) { - Map &m = txxxMap(); - String d = description.upper(); - if(m.contains(d)) - return m[d]; + const String d = description.upper(); + for(size_t i = 0; i < txxxFrameTranslationSize; ++i) { + if(d == txxxFrameTranslation[i][0]) + return txxxFrameTranslation[i][1]; + } return d; } String Frame::keyToTXXX(const String &s) { - static Map m; - if(m.isEmpty()) - for(size_t i = 0; i < txxxFrameTranslationSize; ++i) - m[txxxFrameTranslation[i][1]] = txxxFrameTranslation[i][0]; - if(m.contains(s.upper())) - return m[s]; + const String key = s.upper(); + for(size_t i = 0; i < txxxFrameTranslationSize; ++i) { + if(key == txxxFrameTranslation[i][1]) + return txxxFrameTranslation[i][0]; + } return s; } @@ -532,7 +474,8 @@ // workaround until this function is virtual if(id == "TXXX") return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties(); - else if(id[0] == 'T') + // Apple proprietary WFED (Podcast URL) is in fact a text frame. + else if(id[0] == 'T' || id == "WFED") return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties(); else if(id == "WXXX") return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties(); @@ -552,7 +495,6 @@ void Frame::splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, PropertyMap &tiplProperties, PropertyMap &tmclProperties) { - singleFrameProperties.clear(); tiplProperties.clear(); tmclProperties.clear(); @@ -587,8 +529,8 @@ {} ByteVector frameID; - uint frameSize; - uint version; + unsigned int frameSize; + unsigned int version; // flags @@ -606,12 +548,12 @@ // static members (Frame::Header) //////////////////////////////////////////////////////////////////////////////// -TagLib::uint Frame::Header::size() +unsigned int Frame::Header::size() { return size(4); } -TagLib::uint Frame::Header::size(uint version) +unsigned int Frame::Header::size(unsigned int version) { switch(version) { case 0: @@ -635,7 +577,7 @@ setData(data, synchSafeInts); } -Frame::Header::Header(const ByteVector &data, uint version) +Frame::Header::Header(const ByteVector &data, unsigned int version) { d = new HeaderPrivate; setData(data, version); @@ -648,10 +590,10 @@ void Frame::Header::setData(const ByteVector &data, bool synchSafeInts) { - setData(data, uint(synchSafeInts ? 4 : 3)); + setData(data, static_cast(synchSafeInts ? 4 : 3)); } -void Frame::Header::setData(const ByteVector &data, uint version) +void Frame::Header::setData(const ByteVector &data, unsigned int version) { d->version = version; @@ -792,22 +734,22 @@ d->frameID = id.mid(0, 4); } -TagLib::uint Frame::Header::frameSize() const +unsigned int Frame::Header::frameSize() const { return d->frameSize; } -void Frame::Header::setFrameSize(uint size) +void Frame::Header::setFrameSize(unsigned int size) { d->frameSize = size; } -TagLib::uint Frame::Header::version() const +unsigned int Frame::Header::version() const { return d->version; } -void Frame::Header::setVersion(TagLib::uint version) +void Frame::Header::setVersion(unsigned int version) { d->version = version; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,11 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include +#include #include "id3v2framefactory.h" #include "id3v2synchdata.h" @@ -49,10 +46,45 @@ #include "frames/eventtimingcodesframe.h" #include "frames/chapterframe.h" #include "frames/tableofcontentsframe.h" +#include "frames/podcastframe.h" using namespace TagLib; using namespace ID3v2; +namespace +{ + void updateGenre(TextIdentificationFrame *frame) + { + StringList fields = frame->fieldList(); + StringList newfields; + + for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { + String s = *it; + int end = s.find(")"); + + if(s.startsWith("(") && end > 0) { + // "(12)Genre" + String text = s.substr(end + 1); + bool ok; + int number = s.substr(1, end - 1).toInt(&ok); + if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text)) + newfields.append(s.substr(1, end - 1)); + if(!text.isEmpty()) + newfields.append(text); + } + else { + // "Genre" or "12" + newfields.append(s); + } + } + + if(newfields.isEmpty()) + fields.append(String()); + + frame->setText(newfields); + } +} + class FrameFactory::FrameFactoryPrivate { public: @@ -83,10 +115,10 @@ Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const { - return createFrame(data, uint(synchSafeInts ? 4 : 3)); + return createFrame(data, static_cast(synchSafeInts ? 4 : 3)); } -Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const +Frame *FrameFactory::createFrame(const ByteVector &data, unsigned int version) const { Header tagHeader; tagHeader.setMajorVersion(version); @@ -96,7 +128,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const { ByteVector data = origData; - uint version = tagHeader->majorVersion(); + unsigned int version = tagHeader->majorVersion(); Frame::Header *header = new Frame::Header(data, version); ByteVector frameID = header->frameID(); @@ -104,7 +136,7 @@ // characters. Also make sure that there is data in the frame. if(frameID.size() != (version < 3 ? 3 : 4) || - header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) || + header->frameSize() <= static_cast(header->dataLengthIndicator() ? 4 : 0) || header->frameSize() > data.size()) { delete header; @@ -140,12 +172,11 @@ // TagLib doesn't mess with encrypted frames, so just treat them // as unknown frames. -#if !defined(HAVE_ZLIB) || HAVE_ZLIB == 0 - if(header->compression()) { + if(!zlib::isAvailable() && header->compression()) { debug("Compressed frames are currently not supported."); return new UnknownFrame(data, header); } -#endif + if(header->encryption()) { debug("Encrypted frames are currently not supported."); return new UnknownFrame(data, header); @@ -167,7 +198,8 @@ // Text Identification (frames 4.2) - if(frameID.startsWith("T")) { + // Apple proprietary WFED (Podcast URL) is in fact a text frame. + if(frameID.startsWith("T") || frameID == "WFED") { TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) @@ -287,6 +319,11 @@ if(frameID == "CTOC") return new TableOfContentsFrame(tagHeader, data, header); + // Apple proprietary PCST (Podcast) + + if(frameID == "PCST") + return new PodcastFrame(data, header); + return new UnknownFrame(data, header); } @@ -296,18 +333,27 @@ tag->frameList("TDRC").size() == 1 && tag->frameList("TDAT").size() == 1) { - TextIdentificationFrame *trdc = + TextIdentificationFrame *tdrc = static_cast(tag->frameList("TDRC").front()); - UnknownFrame *tdat = - static_cast(tag->frameList("TDAT").front()); + UnknownFrame *tdat = static_cast(tag->frameList("TDAT").front()); - if(trdc->fieldList().size() == 1 && - trdc->fieldList().front().size() == 4 && + if(tdrc->fieldList().size() == 1 && + tdrc->fieldList().front().size() == 4 && tdat->data().size() >= 5) { String date(tdat->data().mid(1), String::Type(tdat->data()[0])); - if(date.length() == 4) - trdc->setText(trdc->toString() + '-' + date.substr(2, 2) + '-' + date.substr(0, 2)); + if(date.length() == 4) { + tdrc->setText(tdrc->toString() + '-' + date.substr(2, 2) + '-' + date.substr(0, 2)); + if(tag->frameList("TIME").size() == 1) { + UnknownFrame *timeframe = static_cast(tag->frameList("TIME").front()); + if(timeframe->data().size() >= 5) { + String time(timeframe->data().mid(1), String::Type(timeframe->data()[0])); + if(time.length() == 4) { + tdrc->setText(tdrc->toString() + 'T' + time.substr(0, 2) + ':' + time.substr(2, 2)); + } + } + } + } } } } @@ -327,9 +373,9 @@ // protected members //////////////////////////////////////////////////////////////////////////////// -FrameFactory::FrameFactory() +FrameFactory::FrameFactory() : + d(new FrameFactoryPrivate()) { - d = new FrameFactoryPrivate; } FrameFactory::~FrameFactory() @@ -337,9 +383,94 @@ delete d; } +namespace +{ + // Frame conversion table ID3v2.2 -> 2.4 + const char *frameConversion2[][2] = { + { "BUF", "RBUF" }, + { "CNT", "PCNT" }, + { "COM", "COMM" }, + { "CRA", "AENC" }, + { "ETC", "ETCO" }, + { "GEO", "GEOB" }, + { "IPL", "TIPL" }, + { "MCI", "MCDI" }, + { "MLL", "MLLT" }, + { "POP", "POPM" }, + { "REV", "RVRB" }, + { "SLT", "SYLT" }, + { "STC", "SYTC" }, + { "TAL", "TALB" }, + { "TBP", "TBPM" }, + { "TCM", "TCOM" }, + { "TCO", "TCON" }, + { "TCP", "TCMP" }, + { "TCR", "TCOP" }, + { "TDY", "TDLY" }, + { "TEN", "TENC" }, + { "TFT", "TFLT" }, + { "TKE", "TKEY" }, + { "TLA", "TLAN" }, + { "TLE", "TLEN" }, + { "TMT", "TMED" }, + { "TOA", "TOAL" }, + { "TOF", "TOFN" }, + { "TOL", "TOLY" }, + { "TOR", "TDOR" }, + { "TOT", "TOAL" }, + { "TP1", "TPE1" }, + { "TP2", "TPE2" }, + { "TP3", "TPE3" }, + { "TP4", "TPE4" }, + { "TPA", "TPOS" }, + { "TPB", "TPUB" }, + { "TRC", "TSRC" }, + { "TRD", "TDRC" }, + { "TRK", "TRCK" }, + { "TS2", "TSO2" }, + { "TSA", "TSOA" }, + { "TSC", "TSOC" }, + { "TSP", "TSOP" }, + { "TSS", "TSSE" }, + { "TST", "TSOT" }, + { "TT1", "TIT1" }, + { "TT2", "TIT2" }, + { "TT3", "TIT3" }, + { "TXT", "TOLY" }, + { "TXX", "TXXX" }, + { "TYE", "TDRC" }, + { "UFI", "UFID" }, + { "ULT", "USLT" }, + { "WAF", "WOAF" }, + { "WAR", "WOAR" }, + { "WAS", "WOAS" }, + { "WCM", "WCOM" }, + { "WCP", "WCOP" }, + { "WPB", "WPUB" }, + { "WXX", "WXXX" }, + + // Apple iTunes nonstandard frames + { "PCS", "PCST" }, + { "TCT", "TCAT" }, + { "TDR", "TDRL" }, + { "TDS", "TDES" }, + { "TID", "TGID" }, + { "WFD", "WFED" }, + }; + const size_t frameConversion2Size = sizeof(frameConversion2) / sizeof(frameConversion2[0]); + + // Frame conversion table ID3v2.3 -> 2.4 + const char *frameConversion3[][2] = { + { "TORY", "TDOR" }, + { "TYER", "TDRC" }, + { "IPLS", "TIPL" }, + }; + const size_t frameConversion3Size = sizeof(frameConversion3) / sizeof(frameConversion3[0]); +} + bool FrameFactory::updateFrame(Frame::Header *header) const { - TagLib::ByteVector frameID = header->frameID(); + const ByteVector frameID = header->frameID(); switch(header->version()) { @@ -361,67 +492,12 @@ // ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of // the frames to their 4 byte ID3v2.4 equivalent. - convertFrame("BUF", "RBUF", header); - convertFrame("CNT", "PCNT", header); - convertFrame("COM", "COMM", header); - convertFrame("CRA", "AENC", header); - convertFrame("ETC", "ETCO", header); - convertFrame("GEO", "GEOB", header); - convertFrame("IPL", "TIPL", header); - convertFrame("MCI", "MCDI", header); - convertFrame("MLL", "MLLT", header); - convertFrame("POP", "POPM", header); - convertFrame("REV", "RVRB", header); - convertFrame("SLT", "SYLT", header); - convertFrame("STC", "SYTC", header); - convertFrame("TAL", "TALB", header); - convertFrame("TBP", "TBPM", header); - convertFrame("TCM", "TCOM", header); - convertFrame("TCO", "TCON", header); - convertFrame("TCP", "TCMP", header); - convertFrame("TCR", "TCOP", header); - convertFrame("TDY", "TDLY", header); - convertFrame("TEN", "TENC", header); - convertFrame("TFT", "TFLT", header); - convertFrame("TKE", "TKEY", header); - convertFrame("TLA", "TLAN", header); - convertFrame("TLE", "TLEN", header); - convertFrame("TMT", "TMED", header); - convertFrame("TOA", "TOAL", header); - convertFrame("TOF", "TOFN", header); - convertFrame("TOL", "TOLY", header); - convertFrame("TOR", "TDOR", header); - convertFrame("TOT", "TOAL", header); - convertFrame("TP1", "TPE1", header); - convertFrame("TP2", "TPE2", header); - convertFrame("TP3", "TPE3", header); - convertFrame("TP4", "TPE4", header); - convertFrame("TPA", "TPOS", header); - convertFrame("TPB", "TPUB", header); - convertFrame("TRC", "TSRC", header); - convertFrame("TRD", "TDRC", header); - convertFrame("TRK", "TRCK", header); - convertFrame("TS2", "TSO2", header); - convertFrame("TSA", "TSOA", header); - convertFrame("TSC", "TSOC", header); - convertFrame("TSP", "TSOP", header); - convertFrame("TSS", "TSSE", header); - convertFrame("TST", "TSOT", header); - convertFrame("TT1", "TIT1", header); - convertFrame("TT2", "TIT2", header); - convertFrame("TT3", "TIT3", header); - convertFrame("TXT", "TOLY", header); - convertFrame("TXX", "TXXX", header); - convertFrame("TYE", "TDRC", header); - convertFrame("UFI", "UFID", header); - convertFrame("ULT", "USLT", header); - convertFrame("WAF", "WOAF", header); - convertFrame("WAR", "WOAR", header); - convertFrame("WAS", "WOAS", header); - convertFrame("WCM", "WCOM", header); - convertFrame("WCP", "WCOP", header); - convertFrame("WPB", "WPUB", header); - convertFrame("WXX", "WXXX", header); + for(size_t i = 0; i < frameConversion2Size; ++i) { + if(frameID == frameConversion2[i][0]) { + header->setFrameID(frameConversion2[i][1]); + break; + } + } break; } @@ -440,9 +516,12 @@ return false; } - convertFrame("TORY", "TDOR", header); - convertFrame("TYER", "TDRC", header); - convertFrame("IPLS", "TIPL", header); + for(size_t i = 0; i < frameConversion3Size; ++i) { + if(frameID == frameConversion3[i][0]) { + header->setFrameID(frameConversion3[i][1]); + break; + } + } break; } @@ -452,57 +531,11 @@ // This should catch a typo that existed in TagLib up to and including // version 1.1 where TRDC was used for the year rather than TDRC. - convertFrame("TRDC", "TDRC", header); + if(frameID == "TRDC") + header->setFrameID("TDRC"); + break; } return true; } - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void FrameFactory::convertFrame(const char *from, const char *to, - Frame::Header *header) const -{ - if(header->frameID() != from) - return; - - // debug("ID3v2.4 no longer supports the frame type " + String(from) + " It has" + - // "been converted to the type " + String(to) + "."); - - header->setFrameID(to); -} - -void FrameFactory::updateGenre(TextIdentificationFrame *frame) const -{ - StringList fields = frame->fieldList(); - StringList newfields; - - for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { - String s = *it; - int end = s.find(")"); - - if(s.startsWith("(") && end > 0) { - // "(12)Genre" - String text = s.substr(end + 1); - bool ok; - int number = s.substr(1, end - 1).toInt(&ok); - if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text)) - newfields.append(s.substr(1, end - 1)); - if(!text.isEmpty()) - newfields.append(text); - } - else { - // "Genre" or "12" - newfields.append(s); - } - } - - if(newfields.isEmpty()) - fields.append(String::null); - - frame->setText(newfields); - -} diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h 2016-07-19 15:25:23.000000000 +0000 @@ -47,9 +47,9 @@ * Reimplementing this factory is the key to adding support for frame types * not directly supported by TagLib to your application. To do so you would * subclass this factory reimplement createFrame(). Then by setting your - * factory to be the default factory in ID3v2::Tag constructor or with - * MPEG::File::setID3v2FrameFactory() you can implement behavior that will - * allow for new ID3v2::Frame subclasses (also provided by you) to be used. + * factory to be the default factory in ID3v2::Tag constructor you can + * implement behavior that will allow for new ID3v2::Frame subclasses (also + * provided by you) to be used. * * This implements both abstract factory and singleton patterns * of which more information is available on the web and in software design @@ -84,7 +84,7 @@ * \deprecated Please use the method below that accepts a ID3v2::Header * instance in new code. */ - Frame *createFrame(const ByteVector &data, uint version = 4) const; + Frame *createFrame(const ByteVector &data, unsigned int version = 4) const; /*! * Create a frame based on \a data. \a tagHeader should be a valid @@ -152,16 +152,6 @@ FrameFactory(const FrameFactory &); FrameFactory &operator=(const FrameFactory &); - /*! - * This method is used internally to convert a frame from ID \a from to ID - * \a to. If the frame matches the \a from pattern and converts the frame - * ID in the \a header or simply does nothing if the frame ID does not match. - */ - void convertFrame(const char *from, const char *to, - Frame::Header *header) const; - - void updateGenre(TextIdentificationFrame *frame) const; - static FrameFactory factory; class FrameFactoryPrivate; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2frame.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2frame.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2frame.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2frame.h 2016-07-19 15:25:23.000000000 +0000 @@ -79,7 +79,7 @@ /*! * Returns the size of the frame. */ - uint size() const; + unsigned int size() const; /*! * Returns the size of the frame header @@ -89,14 +89,14 @@ * non-binary compatible release this will be made into a non-static * member that checks the internal ID3v2 version. */ - static uint headerSize(); // BIC: remove and make non-static + static unsigned int headerSize(); // BIC: remove and make non-static /*! * Returns the size of the frame header for the given ID3v2 version. * * \deprecated Please see the explanation above. */ - static uint headerSize(uint version); // BIC: remove and make non-static + static unsigned int headerSize(unsigned int version); // BIC: remove and make non-static /*! * Sets the data that will be used as the frame. Since the length is not @@ -242,7 +242,7 @@ */ // BIC: remove and make non-static static String::Type checkEncoding(const StringList &fields, - String::Type encoding, uint version); + String::Type encoding, unsigned int version); /*! * Checks a the list of string values to see if they can be used with the @@ -264,13 +264,13 @@ /*! * Returns an appropriate ID3 frame ID for the given free-form tag key. This method - * will return ByteVector::null if no specialized translation is found. + * will return an empty ByteVector if no specialized translation is found. */ static ByteVector keyToFrameID(const String &); /*! * Returns a free-form tag name for the given ID3 frame ID. Note that this does not work - * for general frame IDs such as TXXX or WXXX; in such a case String::null is returned. + * for general frame IDs such as TXXX or WXXX; in such a case an empty string is returned. */ static String frameIDToKey(const ByteVector &); @@ -343,7 +343,7 @@ * * \a version should be the ID3v2 version of the tag. */ - explicit Header(const ByteVector &data, uint version = 4); + explicit Header(const ByteVector &data, unsigned int version = 4); /*! * Destroys this Header instance. @@ -362,7 +362,7 @@ * Sets the data for the Header. \a version should indicate the ID3v2 * version number of the tag that this frame is contained in. */ - void setData(const ByteVector &data, uint version = 4); + void setData(const ByteVector &data, unsigned int version = 4); /*! * Returns the Frame ID (Structure, 4) @@ -384,24 +384,24 @@ * Returns the size of the frame data portion, as set when setData() was * called or set explicitly via setFrameSize(). */ - uint frameSize() const; + unsigned int frameSize() const; /*! * Sets the size of the frame data portion. */ - void setFrameSize(uint size); + void setFrameSize(unsigned int size); /*! * Returns the ID3v2 version of the header, as passed in from the * construction of the header or set via setVersion(). */ - uint version() const; + unsigned int version() const; /*! * Sets the ID3v2 version of the header, changing has impact on the * correct parsing/rendering of frame data. */ - void setVersion(uint version); + void setVersion(unsigned int version); /*! * Returns the size of the frame header in bytes. @@ -411,7 +411,7 @@ * removed in the next binary incompatible release (2.0) and will be * replaced with a non-static method that checks the frame version. */ - static uint size(); + static unsigned int size(); /*! * Returns the size of the frame header in bytes for the ID3v2 version @@ -419,7 +419,7 @@ * * \deprecated Please see the explanation in the version above. */ - static uint size(uint version); + static unsigned int size(unsigned int version); /*! * Returns true if the flag for tag alter preservation is set. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -39,36 +39,33 @@ class Header::HeaderPrivate { public: - HeaderPrivate() : majorVersion(4), - revisionNumber(0), - unsynchronisation(false), - extendedHeader(false), - experimentalIndicator(false), - footerPresent(false), - tagSize(0) {} + HeaderPrivate() : + majorVersion(4), + revisionNumber(0), + unsynchronisation(false), + extendedHeader(false), + experimentalIndicator(false), + footerPresent(false), + tagSize(0) {} - ~HeaderPrivate() {} - - uint majorVersion; - uint revisionNumber; + unsigned int majorVersion; + unsigned int revisionNumber; bool unsynchronisation; bool extendedHeader; bool experimentalIndicator; bool footerPresent; - uint tagSize; - - static const uint size = 10; + unsigned int tagSize; }; //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// -TagLib::uint Header::size() +unsigned int Header::size() { - return HeaderPrivate::size; + return 10; } ByteVector Header::fileIdentifier() @@ -80,14 +77,14 @@ // public members //////////////////////////////////////////////////////////////////////////////// -Header::Header() +Header::Header() : + d(new HeaderPrivate()) { - d = new HeaderPrivate; } -Header::Header(const ByteVector &data) +Header::Header(const ByteVector &data) : + d(new HeaderPrivate()) { - d = new HeaderPrivate; parse(data); } @@ -96,17 +93,17 @@ delete d; } -TagLib::uint Header::majorVersion() const +unsigned int Header::majorVersion() const { return d->majorVersion; } -void Header::setMajorVersion(TagLib::uint version) +void Header::setMajorVersion(unsigned int version) { d->majorVersion = version; } -TagLib::uint Header::revisionNumber() const +unsigned int Header::revisionNumber() const { return d->revisionNumber; } @@ -131,20 +128,20 @@ return d->footerPresent; } -TagLib::uint Header::tagSize() const +unsigned int Header::tagSize() const { return d->tagSize; } -TagLib::uint Header::completeTagSize() const +unsigned int Header::completeTagSize() const { if(d->footerPresent) - return d->tagSize + d->size + Footer::size(); + return d->tagSize + size() + Footer::size(); else - return d->tagSize + d->size; + return d->tagSize + size(); } -void Header::setTagSize(uint s) +void Header::setTagSize(unsigned int s) { d->tagSize = s; } @@ -199,7 +196,6 @@ if(data.size() < size()) return; - // do some sanity checking -- even in ID3v2.3.0 and less the tag size is a // synch-safe integer, so all bytes must be less than 128. If this is not // true then this is an invalid tag. @@ -216,7 +212,7 @@ } for(ByteVector::ConstIterator it = sizeData.begin(); it != sizeData.end(); it++) { - if(uchar(*it) >= 128) { + if(static_cast(*it) >= 128) { d->tagSize = 0; debug("TagLib::ID3v2::Header::parse() - One of the size bytes in the id3v2 header was greater than the allowed 128."); return; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2header.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2header.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2header.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2header.h 2016-07-19 15:25:23.000000000 +0000 @@ -67,7 +67,7 @@ * Returns the major version number. (Note: This is the 4, not the 2 in * ID3v2.4.0. The 2 is implied.) */ - uint majorVersion() const; + unsigned int majorVersion() const; /*! * Set the the major version number to \a version. (Note: This is @@ -78,13 +78,13 @@ * version which is written and in general should not be called by API * users. */ - void setMajorVersion(uint version); + void setMajorVersion(unsigned int version); /*! * Returns the revision number. (Note: This is the 0, not the 4 in * ID3v2.4.0. The 2 is implied.) */ - uint revisionNumber() const; + unsigned int revisionNumber() const; /*! * Returns true if unsynchronisation has been applied to all frames. @@ -116,7 +116,7 @@ * * \see completeTagSize() */ - uint tagSize() const; + unsigned int tagSize() const; /*! * Returns the tag size, including the header and, if present, the footer @@ -124,18 +124,18 @@ * * \see tagSize() */ - uint completeTagSize() const; + unsigned int completeTagSize() const; /*! * Set the tag size to \a s. * \see tagSize() */ - void setTagSize(uint s); + void setTagSize(unsigned int s); /*! * Returns the size of the header. Presently this is always 10 bytes. */ - static uint size(); + static unsigned int size(); /*! * Returns the string used to identify and ID3v2 tag inside of a file. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -30,9 +30,9 @@ using namespace TagLib; using namespace ID3v2; -TagLib::uint SynchData::toUInt(const ByteVector &data) +unsigned int SynchData::toUInt(const ByteVector &data) { - uint sum = 0; + unsigned int sum = 0; bool notSynchSafe = false; int last = data.size() > 4 ? 3 : data.size() - 1; @@ -62,23 +62,37 @@ return sum; } -ByteVector SynchData::fromUInt(uint value) +ByteVector SynchData::fromUInt(unsigned int value) { ByteVector v(4, 0); for(int i = 0; i < 4; i++) - v[i] = uchar(value >> ((3 - i) * 7) & 0x7f); + v[i] = static_cast(value >> ((3 - i) * 7) & 0x7f); return v; } ByteVector SynchData::decode(const ByteVector &data) { - ByteVector result = data; + // We have this optimized method instead of using ByteVector::replace(), + // since it makes a great difference when decoding huge unsynchronized frames. - ByteVector pattern(2, char(0)); - pattern[0] = '\xFF'; - pattern[1] = '\x00'; + ByteVector result(data.size()); - return result.replace(pattern, '\xFF'); + ByteVector::ConstIterator src = data.begin(); + ByteVector::Iterator dst = result.begin(); + + while(src < data.end() - 1) { + *dst++ = *src++; + + if(*(src - 1) == '\xff' && *src == '\x00') + src++; + } + + if(src < data.end()) + *dst++ = *src++; + + result.resize(static_cast(dst - result.begin())); + + return result; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.h 2016-07-19 15:25:23.000000000 +0000 @@ -51,12 +51,12 @@ * 6.2). The default \a length of * 4 is used if another value is not specified. */ - TAGLIB_EXPORT uint toUInt(const ByteVector &data); + TAGLIB_EXPORT unsigned int toUInt(const ByteVector &data); /*! * Returns a 4 byte (32 bit) synchsafe integer based on \a value. */ - TAGLIB_EXPORT ByteVector fromUInt(uint value); + TAGLIB_EXPORT ByteVector fromUInt(unsigned int value); /*! * Convert the data from unsynchronized data to its original format. diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,21 +23,19 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include -#include "tfile.h" +#include +#include +#include +#include #include "id3v2tag.h" #include "id3v2header.h" #include "id3v2extendedheader.h" #include "id3v2footer.h" #include "id3v2synchdata.h" -#include "tbytevector.h" #include "id3v1genres.h" -#include "tpropertymap.h" -#include "tdebug.h" #include "frames/textidentificationframe.h" #include "frames/commentsframe.h" @@ -49,43 +47,46 @@ using namespace TagLib; using namespace ID3v2; +namespace +{ + const ID3v2::Latin1StringHandler defaultStringHandler; + const ID3v2::Latin1StringHandler *stringHandler = &defaultStringHandler; + + const long MinPaddingSize = 1024; + const long MaxPaddingSize = 1024 * 1024; +} + class ID3v2::Tag::TagPrivate { public: - TagPrivate() : file(0), tagOffset(-1), extendedHeader(0), footer(0), paddingSize(0) + TagPrivate() : + file(0), + tagOffset(0), + extendedHeader(0), + footer(0) { frameList.setAutoDelete(true); } + ~TagPrivate() { delete extendedHeader; delete footer; } + const FrameFactory *factory; + File *file; long tagOffset; - const FrameFactory *factory; Header header; ExtendedHeader *extendedHeader; Footer *footer; - int paddingSize; - FrameListMap frameListMap; FrameList frameList; - - static const Latin1StringHandler *stringHandler; }; -static const Latin1StringHandler defaultStringHandler; -const ID3v2::Latin1StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler; - -namespace -{ - const TagLib::uint DefaultPaddingSize = 1024; -} - //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// @@ -107,20 +108,20 @@ // public members //////////////////////////////////////////////////////////////////////////////// -ID3v2::Tag::Tag() : TagLib::Tag() +ID3v2::Tag::Tag() : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; d->factory = FrameFactory::instance(); } ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) : - TagLib::Tag() + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; - + d->factory = factory; d->file = file; d->tagOffset = tagOffset; - d->factory = factory; read(); } @@ -130,26 +131,25 @@ delete d; } - String ID3v2::Tag::title() const { if(!d->frameListMap["TIT2"].isEmpty()) return d->frameListMap["TIT2"].front()->toString(); - return String::null; + return String(); } String ID3v2::Tag::artist() const { if(!d->frameListMap["TPE1"].isEmpty()) return d->frameListMap["TPE1"].front()->toString(); - return String::null; + return String(); } String ID3v2::Tag::album() const { if(!d->frameListMap["TALB"].isEmpty()) return d->frameListMap["TALB"].front()->toString(); - return String::null; + return String(); } String ID3v2::Tag::comment() const @@ -157,7 +157,7 @@ const FrameList &comments = d->frameListMap["COMM"]; if(comments.isEmpty()) - return String::null; + return String(); for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { @@ -179,7 +179,7 @@ if(d->frameListMap["TCON"].isEmpty() || !dynamic_cast(d->frameListMap["TCON"].front())) { - return String::null; + return String(); } // ID3v2.4 lists genres as the fields in its frames field list. If the field @@ -213,14 +213,14 @@ return genres.toString(); } -TagLib::uint ID3v2::Tag::year() const +unsigned int ID3v2::Tag::year() const { if(!d->frameListMap["TDRC"].isEmpty()) return d->frameListMap["TDRC"].front()->toString().substr(0, 4).toInt(); return 0; } -TagLib::uint ID3v2::Tag::track() const +unsigned int ID3v2::Tag::track() const { if(!d->frameListMap["TRCK"].isEmpty()) return d->frameListMap["TRCK"].front()->toString().toInt(); @@ -284,7 +284,7 @@ #endif } -void ID3v2::Tag::setYear(uint i) +void ID3v2::Tag::setYear(unsigned int i) { if(i <= 0) { removeFrames("TDRC"); @@ -293,7 +293,7 @@ setTextFrame("TDRC", String::number(i)); } -void ID3v2::Tag::setTrack(uint i) +void ID3v2::Tag::setTrack(unsigned int i) { if(i <= 0) { removeFrames("TRCK"); @@ -466,10 +466,18 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const { +#ifdef NO_ITUNES_HACKS const char *unsupportedFrames[] = { "ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG", "TMOO", "TPRO", "TSOA", "TSOT", "TSST", "TSOP", 0 }; +#else + // iTunes writes and reads TSOA, TSOT, TSOP to ID3v2.3. + const char *unsupportedFrames[] = { + "ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG", + "TMOO", "TPRO", "TSST", 0 + }; +#endif ID3v2::TextIdentificationFrame *frameTDOR = 0; ID3v2::TextIdentificationFrame *frameTDRC = 0; ID3v2::TextIdentificationFrame *frameTIPL = 0; @@ -540,14 +548,14 @@ StringList people; if(frameTMCL) { StringList v24People = frameTMCL->fieldList(); - for(uint i = 0; i + 1 < v24People.size(); i += 2) { + for(unsigned int i = 0; i + 1 < v24People.size(); i += 2) { people.append(v24People[i]); people.append(v24People[i+1]); } } if(frameTIPL) { StringList v24People = frameTIPL->fieldList(); - for(uint i = 0; i + 1 < v24People.size(); i += 2) { + for(unsigned int i = 0; i + 1 < v24People.size(); i += 2) { people.append(v24People[i]); people.append(v24People[i+1]); } @@ -558,7 +566,6 @@ } } - ByteVector ID3v2::Tag::render(int version) const { // We need to render the "tag data" first so that we have to correct size to @@ -566,8 +573,6 @@ // in ID3v2::Header::tagSize() -- includes the extended header, frames and // padding, but does not include the tag's header or footer. - ByteVector tagData; - if(version != 3 && version != 4) { debug("Unknown ID3v2 version, using ID3v2.4"); version = 4; @@ -575,7 +580,7 @@ // TODO: Render the extended header. - // Loop through the frames rendering them and adding them to the tagData. + // Downgrade the frames that ID3v2.3 doesn't support. FrameList newFrames; newFrames.setAutoDelete(true); @@ -588,6 +593,12 @@ downgradeFrames(&frameList, &newFrames); } + // Reserve a 10-byte blank space for an ID3v2 tag header. + + ByteVector tagData(Header::size(), '\0'); + + // Loop through the frames rendering them and adding them to the tagData. + for(FrameList::ConstIterator it = frameList.begin(); it != frameList.end(); it++) { (*it)->header()->setVersion(version); if((*it)->header()->frameID().size() != 4) { @@ -607,42 +618,49 @@ } // Compute the amount of padding, and append that to tagData. + // TODO: Should be calculated in long long in taglib2. - uint paddingSize = DefaultPaddingSize; + long originalSize = d->header.tagSize(); + long paddingSize = originalSize - (tagData.size() - Header::size()); - if(d->file && tagData.size() < d->header.tagSize()) { - paddingSize = d->header.tagSize() - tagData.size(); + if(paddingSize <= 0) { + paddingSize = MinPaddingSize; + } + else { + // Padding won't increase beyond 1% of the file size or 1MB. - // Padding won't increase beyond 1% of the file size. + long threshold = d->file ? d->file->length() / 100 : 0; + threshold = std::max(threshold, MinPaddingSize); + threshold = std::min(threshold, MaxPaddingSize); - if(paddingSize > DefaultPaddingSize) { - const uint threshold = d->file->length() / 100; // should be ulonglong in taglib2. - if(paddingSize > threshold) - paddingSize = DefaultPaddingSize; - } + if(paddingSize > threshold) + paddingSize = MinPaddingSize; } - tagData.append(ByteVector(paddingSize, '\0')); + tagData.resize(static_cast(tagData.size() + paddingSize), '\0'); // Set the version and data size. d->header.setMajorVersion(version); - d->header.setTagSize(tagData.size()); + d->header.setTagSize(tagData.size() - Header::size()); // TODO: This should eventually include d->footer->render(). - return d->header.render() + tagData; + const ByteVector headerData = d->header.render(); + std::copy(headerData.begin(), headerData.end(), tagData.begin()); + + return tagData; } Latin1StringHandler const *ID3v2::Tag::latin1StringHandler() { - return TagPrivate::stringHandler; + return stringHandler; } void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler) { if(handler) - TagPrivate::stringHandler = handler; + stringHandler = handler; else - TagPrivate::stringHandler = &defaultStringHandler; + stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// @@ -651,18 +669,43 @@ void ID3v2::Tag::read() { - if(d->file && d->file->isOpen()) { + if(!d->file) + return; - d->file->seek(d->tagOffset); - d->header.setData(d->file->readBlock(Header::size())); + if(!d->file->isOpen()) + return; - // if the tag size is 0, then this is an invalid tag (tags must contain at - // least one frame) + d->file->seek(d->tagOffset); + d->header.setData(d->file->readBlock(Header::size())); - if(d->header.tagSize() == 0) - return; + // If the tag size is 0, then this is an invalid tag (tags must contain at + // least one frame) + if(d->header.tagSize() != 0) parse(d->file->readBlock(d->header.tagSize())); + + // Look for duplicate ID3v2 tags and treat them as an extra blank of this one. + // It leads to overwriting them with zero when saving the tag. + + // This is a workaround for some faulty files that have duplicate ID3v2 tags. + // Unfortunately, TagLib itself may write such duplicate tags until v1.10. + + unsigned int extraSize = 0; + + while(true) { + + d->file->seek(d->tagOffset + d->header.completeTagSize() + extraSize); + + const ByteVector data = d->file->readBlock(Header::size()); + if(data.size() < Header::size() || !data.startsWith(Header::fileIdentifier())) + break; + + extraSize += Header(data).completeTagSize(); + } + + if(extraSize != 0) { + debug("ID3v2::Tag::read() - Duplicate ID3v2 tags found."); + d->header.setTagSize(d->header.tagSize() + extraSize); } } @@ -673,8 +716,8 @@ if(d->header.unsynchronisation() && d->header.majorVersion() <= 3) data = SynchData::decode(data); - uint frameDataPosition = 0; - uint frameDataLength = data.size(); + unsigned int frameDataPosition = 0; + unsigned int frameDataLength = data.size(); // check for extended header @@ -710,7 +753,6 @@ debug("Padding *and* a footer found. This is not allowed by the spec."); } - d->paddingSize = frameDataLength - frameDataPosition; break; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2tag.h clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2tag.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/id3v2/id3v2tag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/id3v2/id3v2tag.h 2016-07-19 15:25:23.000000000 +0000 @@ -169,16 +169,16 @@ virtual String album() const; virtual String comment() const; virtual String genre() const; - virtual uint year() const; - virtual uint track() const; + virtual unsigned int year() const; + virtual unsigned int track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); - virtual void setYear(uint i); - virtual void setTrack(uint i); + virtual void setYear(unsigned int i); + virtual void setTrack(unsigned int i); virtual bool isEmpty() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegfile.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -24,6 +24,7 @@ ***************************************************************************/ #include +#include #include #include #include @@ -33,51 +34,27 @@ #include "mpegfile.h" #include "mpegheader.h" +#include "mpegutils.h" #include "tpropertymap.h" using namespace TagLib; namespace { - /*! - * MPEG frames can be recognized by the bit pattern 11111111 111, so the - * first byte is easy to check for, however checking to see if the second byte - * starts with \e 111 is a bit more tricky, hence these functions. - */ - - inline bool firstSyncByte(uchar byte) - { - return (byte == 0xFF); - } - - inline bool secondSynchByte(uchar byte) - { - return ((byte & 0xE0) == 0xE0); - } -} - -namespace -{ enum { ID3v2Index = 0, APEIndex = 1, ID3v1Index = 2 }; } class MPEG::File::FilePrivate { public: - FilePrivate(ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : + FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : ID3v2FrameFactory(frameFactory), ID3v2Location(-1), ID3v2OriginalSize(0), APELocation(-1), - APEFooterLocation(-1), APEOriginalSize(0), ID3v1Location(-1), - hasID3v2(false), - hasID3v1(false), - hasAPE(false), - properties(0) - { - } + properties(0) {} ~FilePrivate() { @@ -87,23 +64,15 @@ const ID3v2::FrameFactory *ID3v2FrameFactory; long ID3v2Location; - uint ID3v2OriginalSize; + long ID3v2OriginalSize; long APELocation; - long APEFooterLocation; - uint APEOriginalSize; + long APEOriginalSize; long ID3v1Location; TagUnion tag; - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasID3v2; - bool hasID3v1; - bool hasAPE; - Properties *properties; }; @@ -149,33 +118,22 @@ PropertyMap MPEG::File::properties() const { - // once Tag::properties() is virtual, this case distinction could actually be done - // within TagUnion. - if(d->hasID3v2) - return d->tag.access(ID3v2Index, false)->properties(); - if(d->hasAPE) - return d->tag.access(APEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access(ID3v1Index, false)->properties(); - return PropertyMap(); + return d->tag.properties(); } void MPEG::File::removeUnsupportedProperties(const StringList &properties) { - if(d->hasID3v2) - d->tag.access(ID3v2Index, false)->removeUnsupportedProperties(properties); - else if(d->hasAPE) - d->tag.access(APEIndex, false)->removeUnsupportedProperties(properties); - else if(d->hasID3v1) - d->tag.access(ID3v1Index, false)->removeUnsupportedProperties(properties); + d->tag.removeUnsupportedProperties(properties); } PropertyMap MPEG::File::setProperties(const PropertyMap &properties) { - if(d->hasID3v1) - // update ID3v1 tag if it exists, but ignore the return value - d->tag.access(ID3v1Index, false)->setProperties(properties); - return d->tag.access(ID3v2Index, true)->setProperties(properties); + // update ID3v1 tag if it exists, but ignore the return value + + if(ID3v1Tag()) + ID3v1Tag()->setProperties(properties); + + return ID3v2Tag(true)->setProperties(properties); } MPEG::Properties *MPEG::File::audioProperties() const @@ -205,17 +163,6 @@ bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags) { - if(tags == NoTags && stripOthers) - return strip(AllTags); - - if(!ID3v2Tag() && !ID3v1Tag() && !APETag()) { - - if((d->hasID3v1 || d->hasID3v2 || d->hasAPE) && stripOthers) - return strip(AllTags); - - return true; - } - if(readOnly()) { debug("MPEG::File::save() -- File is read only."); return false; @@ -223,7 +170,7 @@ // Create the tags if we've been asked to. - if (duplicateTags) { + if(duplicateTags) { // Copy the values from the tag that does exist into the new tag, // except if the existing tag is to be stripped. @@ -235,79 +182,93 @@ Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false); } - bool success = true; + // Remove all the tags not going to be saved. + + if(stripOthers) + strip(~tags, false); if(ID3v2 & tags) { if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { - if(!d->hasID3v2) + // ID3v2 tag is not empty. Update the old one or create a new one. + + if(d->ID3v2Location < 0) d->ID3v2Location = 0; - insert(ID3v2Tag()->render(id3v2Version), d->ID3v2Location, d->ID3v2OriginalSize); + const ByteVector data = ID3v2Tag()->render(id3v2Version); + insert(data, d->ID3v2Location, d->ID3v2OriginalSize); - d->hasID3v2 = true; + if(d->APELocation >= 0) + d->APELocation += (static_cast(data.size()) - d->ID3v2OriginalSize); - // v1 tag location has changed, update if it exists + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->ID3v2OriginalSize); - if(ID3v1Tag()) - d->ID3v1Location = findID3v1(); + d->ID3v2OriginalSize = data.size(); + } + else { - // APE tag location has changed, update if it exists + // ID3v2 tag is empty. Remove the old one. - if(APETag()) - findAPE(); + strip(ID3v2, false); } - else if(stripOthers) - success = strip(ID3v2, false) && success; } - else if(d->hasID3v2 && stripOthers) - success = strip(ID3v2) && success; if(ID3v1 & tags) { + if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { - int offset = d->hasID3v1 ? -128 : 0; - seek(offset, End); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; - d->ID3v1Location = findID3v1(); - } - else if(stripOthers) - success = strip(ID3v1) && success; - } - else if(d->hasID3v1 && stripOthers) - success = strip(ID3v1, false) && success; - // Dont save an APE-tag unless one has been created + // ID3v1 tag is not empty. Update the old one or create a new one. - if((APE & tags) && APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APEOriginalSize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APEOriginalSize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APEOriginalSize; + if(d->ID3v1Location >= 0) { + seek(d->ID3v1Location); } else { seek(0, End); - d->APELocation = tell(); - APE::Tag *apeTag = d->tag.access(APEIndex, false); - d->APEFooterLocation = d->APELocation - + apeTag->footer()->completeTagSize() - - APE::Footer::size(); - writeBlock(APETag()->render()); - d->APEOriginalSize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; + d->ID3v1Location = tell(); } + + writeBlock(ID3v1Tag()->render()); + } + else { + + // ID3v1 tag is empty. Remove the old one. + + strip(ID3v1, false); } } - else if(d->hasAPE && stripOthers) - success = strip(APE, false) && success; - return success; + if(APE & tags) { + + if(APETag() && !APETag()->isEmpty()) { + + // APE tag is not empty. Update the old one or create a new one. + + if(d->APELocation < 0) { + if(d->ID3v1Location >= 0) + d->APELocation = d->ID3v1Location; + else + d->APELocation = length(); + } + + const ByteVector data = APETag()->render(); + insert(data, d->APELocation, d->APEOriginalSize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->APEOriginalSize); + + d->APEOriginalSize = data.size(); + } + else { + + // APE tag is empty. Remove the old one. + + strip(APE, false); + } + } + + return true; } ID3v2::Tag *MPEG::File::ID3v2Tag(bool create) @@ -337,44 +298,39 @@ return false; } - if((tags & ID3v2) && d->hasID3v2) { + if((tags & ID3v2) && d->ID3v2Location >= 0) { removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); + + if(d->APELocation >= 0) + d->APELocation -= d->ID3v2OriginalSize; + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->ID3v2OriginalSize; + d->ID3v2Location = -1; d->ID3v2OriginalSize = 0; - d->hasID3v2 = false; if(freeMemory) d->tag.set(ID3v2Index, 0); - - // v1 tag location has changed, update if it exists - - if(ID3v1Tag()) - d->ID3v1Location = findID3v1(); - - // APE tag location has changed, update if it exists - - if(APETag()) - findAPE(); } - if((tags & ID3v1) && d->hasID3v1) { + if((tags & ID3v1) && d->ID3v1Location >= 0) { truncate(d->ID3v1Location); + d->ID3v1Location = -1; - d->hasID3v1 = false; if(freeMemory) d->tag.set(ID3v1Index, 0); } - if((tags & APE) && d->hasAPE) { + if((tags & APE) && d->APELocation >= 0) { removeBlock(d->APELocation, d->APEOriginalSize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->APEOriginalSize; + d->APELocation = -1; - d->APEFooterLocation = -1; - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) - d->ID3v1Location -= d->APEOriginalSize; - } + d->APEOriginalSize = 0; if(freeMemory) d->tag.set(APEIndex, 0); @@ -404,7 +360,7 @@ if(foundLastSyncPattern && secondSynchByte(buffer[0])) return position - 1; - for(uint i = 0; i < buffer.size() - 1; i++) { + for(unsigned int i = 0; i < buffer.size() - 1; i++) { if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1])) return position + i; } @@ -420,7 +376,7 @@ ByteVector buffer; while (position > 0) { - long size = ulong(position) < bufferSize() ? position : bufferSize(); + long size = std::min(position, bufferSize()); position -= size; seek(position); @@ -446,45 +402,39 @@ { long position = 0; - if(hasID3v2Tag()) { + if(hasID3v2Tag()) position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize(); - // Skip duplicate ID3v2 tags. - - // Workaround for some faulty files that have duplicate ID3v2 tags. - // Combination of EAC and LAME creates such files when configured incorrectly. - - long location; - while((location = findID3v2(position)) >= 0) { - seek(location); - const ID3v2::Header header(readBlock(ID3v2::Header::size())); - position = location + header.completeTagSize(); - - debug("MPEG::File::firstFrameOffset() - Duplicate ID3v2 tag found."); - } - } - return nextFrameOffset(position); } long MPEG::File::lastFrameOffset() { - return previousFrameOffset(hasID3v1Tag() ? d->ID3v1Location - 1 : length()); + long position; + + if(hasAPETag()) + position = d->APELocation - 1; + else if(hasID3v1Tag()) + position = d->ID3v1Location - 1; + else + position = length(); + + return previousFrameOffset(position); } bool MPEG::File::hasID3v1Tag() const { - return d->hasID3v1; + return (d->ID3v1Location >= 0); } bool MPEG::File::hasID3v2Tag() const { - return d->hasID3v2; + return (d->ID3v2Location >= 0); } bool MPEG::File::hasAPETag() const { - return d->hasAPE; + return (d->APELocation >= 0); } //////////////////////////////////////////////////////////////////////////////// @@ -495,38 +445,28 @@ { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(0); + d->ID3v2Location = findID3v2(); if(d->ID3v2Location >= 0) { - d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); - d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); - - if(ID3v2Tag()->header()->tagSize() <= 0) - d->tag.set(ID3v2Index, 0); - else - d->hasID3v2 = true; } // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); - if(d->ID3v1Location >= 0) { + if(d->ID3v1Location >= 0) d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } // Look for an APE tag - findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { - - d->tag.set(APEIndex, new APE::Tag(this, d->APEFooterLocation)); + d->tag.set(APEIndex, new APE::Tag(this, d->APELocation)); d->APEOriginalSize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; + d->APELocation = d->APELocation + APE::Footer::size() - d->APEOriginalSize; } if(readProperties) @@ -538,146 +478,38 @@ ID3v1Tag(true); } -long MPEG::File::findID3v2(long offset) +long MPEG::File::findID3v2() { - // This method is based on the contents of TagLib::File::find(), but because - // of some subtleties -- specifically the need to look for the bit pattern of - // an MPEG sync, it has been modified for use here. - - if(isValid() && ID3v2::Header::fileIdentifier().size() <= bufferSize()) { - - // The position in the file that the current buffer starts at. - - long bufferOffset = 0; - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - int previousPartialMatch = -1; - bool previousPartialSynchMatch = false; - - // Save the location of the current read pointer. We will restore the - // position using seek() before all returns. + if(!isValid()) + return -1; - long originalPosition = tell(); + // An ID3v2 tag or MPEG frame is most likely be at the beginning of the file. - // Start the search at the offset. + const ByteVector headerID = ID3v2::Header::fileIdentifier(); - seek(offset); + seek(0); - // This loop is the crux of the find method. There are three cases that we - // want to account for: - // (1) The previously searched buffer contained a partial match of the search - // pattern and we want to see if the next one starts with the remainder of - // that pattern. - // - // (2) The search pattern is wholly contained within the current buffer. - // - // (3) The current buffer ends with a partial match of the pattern. We will - // note this for use in the next iteration, where we will check for the rest - // of the pattern. + const ByteVector data = readBlock(headerID.size()); + if(data.size() < headerID.size()) + return -1; - for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { - - // (1) previous partial match - - if(previousPartialSynchMatch && secondSynchByte(buffer[0])) - return -1; - - if(previousPartialMatch >= 0 && int(bufferSize()) > previousPartialMatch) { - const int patternOffset = (bufferSize() - previousPartialMatch); - if(buffer.containsAt(ID3v2::Header::fileIdentifier(), 0, patternOffset)) { - seek(originalPosition); - return offset + bufferOffset - bufferSize() + previousPartialMatch; - } - } - - // (2) pattern contained in current buffer - - long location = buffer.find(ID3v2::Header::fileIdentifier()); - if(location >= 0) { - seek(originalPosition); - return offset + bufferOffset + location; - } + if(data == headerID) + return 0; - int firstSynchByte = buffer.find(char(uchar(255))); + if(firstSyncByte(data[0]) && secondSynchByte(data[1])) + return -1; - // Here we have to loop because there could be several of the first - // (11111111) byte, and we want to check all such instances until we find - // a full match (11111111 111) or hit the end of the buffer. + // Look for the entire file, if neither an MEPG frame or ID3v2 tag was found + // at the beginning of the file. + // We don't care about the inefficiency of the code, since this is a seldom case. - while(firstSynchByte >= 0) { + const long tagOffset = find(headerID); + if(tagOffset < 0) + return -1; - // if this *is not* at the end of the buffer - - if(firstSynchByte < int(buffer.size()) - 1) { - if(secondSynchByte(buffer[firstSynchByte + 1])) { - // We've found the frame synch pattern. - seek(originalPosition); - return -1; - } - else { - - // We found 11111111 at the end of the current buffer indicating a - // partial match of the synch pattern. The find() below should - // return -1 and break out of the loop. - - previousPartialSynchMatch = true; - } - } - - // Check in the rest of the buffer. - - firstSynchByte = buffer.find(char(uchar(255)), firstSynchByte + 1); - } - - // (3) partial match - - previousPartialMatch = buffer.endsWithPartialMatch(ID3v2::Header::fileIdentifier()); - - bufferOffset += bufferSize(); - } - - // Since we hit the end of the file, reset the status before continuing. - - clear(); - - seek(originalPosition); - } - - return -1; -} - -long MPEG::File::findID3v1() -{ - if(isValid()) { - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - } - return -1; -} - -void MPEG::File::findAPE() -{ - if(isValid()) { - seek(d->hasID3v1 ? -160 : -32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) { - d->APEFooterLocation = p; - seek(d->APEFooterLocation); - APE::Footer footer(readBlock(APE::Footer::size())); - d->APELocation = d->APEFooterLocation - footer.completeTagSize() - + APE::Footer::size(); - return; - } - } + const long frameOffset = firstFrameOffset(); + if(frameOffset < tagOffset) + return -1; - d->APELocation = -1; - d->APEFooterLocation = -1; + return tagOffset; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegfile.h clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegfile.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -175,9 +175,6 @@ * If you would like more granular control over the content of the tags, * with the concession of generality, use parameterized save call below. * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. - * * \see save(int tags) */ virtual bool save(); @@ -190,9 +187,6 @@ * This strips all tags not included in the mask, but does not modify them * in memory, so later calls to save() which make use of these tags will * remain valid. This also strips empty tags. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ bool save(int tags); @@ -204,9 +198,6 @@ * If \a stripOthers is true this strips all tags not included in the mask, * but does not modify them in memory, so later calls to save() which make * use of these tags will remain valid. This also strips empty tags. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ // BIC: combine with the above method bool save(int tags, bool stripOthers); @@ -222,9 +213,6 @@ * * The \a id3v2Version parameter specifies the version of the saved * ID3v2 tag. It can be either 4 or 3. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ // BIC: combine with the above method bool save(int tags, bool stripOthers, int id3v2Version); @@ -243,9 +231,6 @@ * * If \a duplicateTags is true and at least one tag -- ID3v1 or ID3v2 -- * exists this will duplicate its content into the other tag. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ // BIC: combine with the above method bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags); @@ -390,9 +375,7 @@ File &operator=(const File &); void read(bool readProperties); - long findID3v2(long offset); - long findID3v1(); - void findAPE(); + long findID3v2(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegheader.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegheader.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegheader.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegheader.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,14 +23,14 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include - #include #include +#include #include -#include "trefcounter.h" +#include #include "mpegheader.h" +#include "mpegutils.h" using namespace TagLib; @@ -42,6 +42,7 @@ version(Version1), layer(0), protectionEnabled(false), + bitrate(0), sampleRate(0), isPadded(false), channelMode(Stereo), @@ -68,20 +69,27 @@ // public members //////////////////////////////////////////////////////////////////////////////// -MPEG::Header::Header(const ByteVector &data) +MPEG::Header::Header(const ByteVector &data) : + d(new HeaderPrivate()) +{ + debug("MPEG::Header::Header() - This constructor is no longer used."); +} + +MPEG::Header::Header(File *file, long offset, bool checkLength) : + d(new HeaderPrivate()) { - d = new HeaderPrivate; - parse(data); + parse(file, offset, checkLength); } -MPEG::Header::Header(const Header &h) : d(h.d) +MPEG::Header::Header(const Header &h) : + d(h.d) { d->ref(); } MPEG::Header::~Header() { - if (d->deref()) + if(d->deref()) delete d; } @@ -162,41 +170,54 @@ // private members //////////////////////////////////////////////////////////////////////////////// -void MPEG::Header::parse(const ByteVector &data) +void MPEG::Header::parse(File *file, long offset, bool checkLength) { - if(data.size() < 4 || uchar(data[0]) != 0xff) { - debug("MPEG::Header::parse() -- First byte did not match MPEG synch."); + file->seek(offset); + const ByteVector data = file->readBlock(4); + + if(data.size() < 4) { + debug("MPEG::Header::parse() -- data is too short for an MPEG frame header."); return; } - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt())); - - // Check for the second byte's part of the MPEG synch + // Check for the MPEG synch bytes. - if(!flags[23] || !flags[22] || !flags[21]) { - debug("MPEG::Header::parse() -- Second byte did not match MPEG synch."); + if(!firstSyncByte(data[0]) || !secondSynchByte(data[1])) { + debug("MPEG::Header::parse() -- MPEG header did not match MPEG synch."); return; } // Set the MPEG version - if(!flags[20] && !flags[19]) + const int versionBits = (static_cast(data[1]) >> 3) & 0x03; + + if(versionBits == 0) d->version = Version2_5; - else if(flags[20] && !flags[19]) + else if(versionBits == 2) d->version = Version2; - else if(flags[20] && flags[19]) + else if(versionBits == 3) d->version = Version1; + else { + debug("MPEG::Header::parse() -- Invalid MPEG version bits."); + return; + } // Set the MPEG layer - if(!flags[18] && flags[17]) + const int layerBits = (static_cast(data[1]) >> 1) & 0x03; + + if(layerBits == 1) d->layer = 3; - else if(flags[18] && !flags[17]) + else if(layerBits == 2) d->layer = 2; - else if(flags[18] && flags[17]) + else if(layerBits == 3) d->layer = 1; + else { + debug("MPEG::Header::parse() -- Invalid MPEG layer bits."); + return; + } - d->protectionEnabled = !flags[16]; + d->protectionEnabled = (static_cast(data[1] & 0x01) == 0); // Set the bitrate @@ -219,9 +240,14 @@ // The bitrate index is encoded as the first 4 bits of the 3rd byte, // i.e. 1111xxxx - int i = uchar(data[2]) >> 4; + const int bitrateIndex = (static_cast(data[2]) >> 4) & 0x0F; - d->bitrate = bitrates[versionIndex][layerIndex][i]; + d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex]; + + if(d->bitrate == 0) { + debug("MPEG::Header::parse() -- Invalid bit rate."); + return; + } // Set the sample rate @@ -233,9 +259,9 @@ // The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx - i = uchar(data[2]) >> 2 & 0x03; + const int samplerateIndex = (static_cast(data[2]) >> 2) & 0x03; - d->sampleRate = sampleRates[d->version][i]; + d->sampleRate = sampleRates[d->version][samplerateIndex]; if(d->sampleRate == 0) { debug("MPEG::Header::parse() -- Invalid sample rate."); @@ -245,13 +271,13 @@ // The channel mode is encoded as a 2 bit value at the end of the 3nd byte, // i.e. xxxxxx11 - d->channelMode = ChannelMode((uchar(data[3]) & 0xC0) >> 6); + d->channelMode = static_cast((static_cast(data[3]) >> 6) & 0x03); // TODO: Add mode extension for completeness - d->isOriginal = flags[2]; - d->isCopyrighted = flags[3]; - d->isPadded = flags[9]; + d->isOriginal = ((static_cast(data[3]) & 0x04) != 0); + d->isCopyrighted = ((static_cast(data[3]) & 0x08) != 0); + d->isPadded = ((static_cast(data[2]) & 0x02) != 0); // Samples per frame @@ -273,6 +299,34 @@ if(d->isPadded) d->frameLength += paddingSize[layerIndex]; + if(checkLength) { + + // Check if the frame length has been calculated correctly, or the next frame + // header is right next to the end of this frame. + + // The MPEG versions, layers and sample rates of the two frames should be + // consistent. Otherwise, we assume that either or both of the frames are + // broken. + + file->seek(offset + d->frameLength); + const ByteVector nextData = file->readBlock(4); + + if(nextData.size() < 4) { + debug("MPEG::Header::parse() -- Could not read the next frame header."); + return; + } + + const unsigned int HeaderMask = 0xfffe0c00; + + const unsigned int header = data.toUInt(0, true) & HeaderMask; + const unsigned int nextHeader = nextData.toUInt(0, true) & HeaderMask; + + if(header != nextHeader) { + debug("MPEG::Header::parse() -- The next frame was not consistent with this frame."); + return; + } + } + // Now that we're done parsing, set this to be a valid frame. d->isValid = true; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegheader.h clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegheader.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegheader.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegheader.h 2016-07-19 15:25:23.000000000 +0000 @@ -31,6 +31,7 @@ namespace TagLib { class ByteVector; + class File; namespace MPEG { @@ -48,10 +49,21 @@ public: /*! * Parses an MPEG header based on \a data. + * + * \deprecated */ Header(const ByteVector &data); /*! + * Parses an MPEG header based on \a file and \a offset. + * + * \note If \a checkLength is true, this requires the next MPEG frame to + * check if the frame length is parsed and calculated correctly. So it's + * suitable for seeking for the first valid frame. + */ + Header(File *file, long offset, bool checkLength = true); + + /*! * Does a shallow copy of \a h. */ Header(const Header &h); @@ -155,7 +167,7 @@ Header &operator=(const Header &h); private: - void parse(const ByteVector &data); + void parse(File *file, long offset, bool checkLength); class HeaderPrivate; HeaderPrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegproperties.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -155,27 +155,31 @@ void MPEG::Properties::read(File *file) { - // Only the first frame is required if we have a VBR header. + // Only the first valid frame is required if we have a VBR header. - const long first = file->firstFrameOffset(); - if(first < 0) { - debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); + long firstFrameOffset = file->firstFrameOffset(); + if(firstFrameOffset < 0) { + debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream."); return; } - file->seek(first); - const Header firstHeader(file->readBlock(4)); + Header firstHeader(file, firstFrameOffset); - if(!firstHeader.isValid()) { - debug("MPEG::Properties::read() -- The first page header is invalid."); - return; + while(!firstHeader.isValid()) { + firstFrameOffset = file->nextFrameOffset(firstFrameOffset + 1); + if(firstFrameOffset < 0) { + debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); + return; + } + + firstHeader = Header(file, firstFrameOffset); } // Check for a VBR header that will help us in gathering information about a // VBR stream. - file->seek(first + 4); - d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength() - 4)); + file->seek(firstFrameOffset); + d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength())); if(!d->xingHeader->isValid()) { delete d->xingHeader; d->xingHeader = 0; @@ -201,14 +205,27 @@ d->bitrate = firstHeader.bitrate(); - long streamLength = file->length() - first; + // Look for the last MPEG audio frame to calculate the stream length. - if(file->hasID3v1Tag()) - streamLength -= 128; + long lastFrameOffset = file->lastFrameOffset(); + if(lastFrameOffset < 0) { + debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream."); + return; + } + + Header lastHeader(file, lastFrameOffset, false); + + while(!lastHeader.isValid()) { + lastFrameOffset = file->previousFrameOffset(lastFrameOffset); + if(lastFrameOffset < 0) { + debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream."); + return; + } - if(file->hasAPETag()) - streamLength -= file->APETag()->footer()->completeTagSize(); + lastHeader = Header(file, lastFrameOffset, false); + } + const long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength(); if(streamLength > 0) d->length = static_cast(streamLength * 8.0 / d->bitrate + 0.5); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegutils.h clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegutils.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/mpegutils.h 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/mpegutils.h 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,63 @@ +/*************************************************************************** + copyright : (C) 2015 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_MPEGUTILS_H +#define TAGLIB_MPEGUTILS_H + +// THIS FILE IS NOT A PART OF THE TAGLIB API + +#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header + +namespace TagLib +{ + namespace MPEG + { + namespace + { + + /*! + * MPEG frames can be recognized by the bit pattern 11111111 111, so the + * first byte is easy to check for, however checking to see if the second byte + * starts with \e 111 is a bit more tricky, hence these functions. + */ + inline bool firstSyncByte(unsigned char byte) + { + return (byte == 0xFF); + } + + inline bool secondSynchByte(unsigned char byte) + { + // 0xFF is possible in theory, but it's very unlikely be a header. + + return (byte != 0xFF && ((byte & 0xE0) == 0xE0)); + } + + } + } +} + +#endif + +#endif diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/xingheader.cpp clementine-1.3.1-218/3rdparty/taglib/mpeg/xingheader.cpp --- clementine-1.3.1-217/3rdparty/taglib/mpeg/xingheader.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/xingheader.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -40,8 +40,8 @@ size(0), type(MPEG::XingHeader::Invalid) {} - uint frames; - uint size; + unsigned int frames; + unsigned int size; MPEG::XingHeader::HeaderType type; }; @@ -66,12 +66,12 @@ return (d->type != Invalid && d->frames > 0 && d->size > 0); } -TagLib::uint MPEG::XingHeader::totalFrames() const +unsigned int MPEG::XingHeader::totalFrames() const { return d->frames; } -TagLib::uint MPEG::XingHeader::totalSize() const +unsigned int MPEG::XingHeader::totalSize() const { return d->size; } @@ -103,7 +103,7 @@ // Xing header found. - if(data.size() < static_cast(offset + 16)) { + if(data.size() < static_cast(offset + 16)) { debug("MPEG::XingHeader::parse() -- Xing header found but too short."); return; } @@ -127,7 +127,7 @@ // VBRI header found. - if(data.size() < static_cast(offset + 32)) { + if(data.size() < static_cast(offset + 32)) { debug("MPEG::XingHeader::parse() -- VBRI header found but too short."); return; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/mpeg/xingheader.h clementine-1.3.1-218/3rdparty/taglib/mpeg/xingheader.h --- clementine-1.3.1-217/3rdparty/taglib/mpeg/xingheader.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/mpeg/xingheader.h 2016-07-19 15:25:23.000000000 +0000 @@ -93,12 +93,12 @@ /*! * Returns the total number of frames. */ - uint totalFrames() const; + unsigned int totalFrames() const; /*! * Returns the total size of stream in bytes. */ - uint totalSize() const; + unsigned int totalSize() const; /*! * Returns the type of the VBR header. diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/flac/oggflacfile.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/flac/oggflacfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/flac/oggflacfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/flac/oggflacfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -247,7 +247,7 @@ char blockType = header[0] & 0x7f; bool lastBlock = (header[0] & 0x80) != 0; - uint length = header.toUInt(1, 3, true); + unsigned int length = header.toUInt(1, 3, true); overhead += length; // Sanity: First block should be the stream_info metadata diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/oggfile.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/oggfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/oggfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/oggfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -34,15 +34,24 @@ using namespace TagLib; +namespace +{ + // Returns the first packet index of the right next page to the given one. + unsigned int nextPacketIndex(const Ogg::Page *page) + { + if(page->header()->lastPacketCompleted()) + return page->firstPacketIndex() + page->packetCount(); + else + return page->firstPacketIndex() + page->packetCount() - 1; + } +} + class Ogg::File::FilePrivate { public: FilePrivate() : - streamSerialNumber(0), firstPageHeader(0), - lastPageHeader(0), - currentPage(0), - currentPacketPage(0) + lastPageHeader(0) { pages.setAutoDelete(true); } @@ -53,20 +62,11 @@ delete lastPageHeader; } - uint streamSerialNumber; + unsigned int streamSerialNumber; List pages; PageHeader *firstPageHeader; PageHeader *lastPageHeader; - std::vector< List > packetToPageMap; - Map dirtyPackets; - List dirtyPages; - - //! The current page for the reader -- used by nextPage() - Page *currentPage; - //! The current page for the packet parser -- used by packet() - Page *currentPacketPage; - //! The packets for the currentPacketPage -- used by packet() - ByteVectorList currentPackets; + Map dirtyPackets; }; //////////////////////////////////////////////////////////////////////////////// @@ -78,7 +78,7 @@ delete d; } -ByteVector Ogg::File::packet(uint i) +ByteVector Ogg::File::packet(unsigned int i) { // Check to see if we're called setPacket() for this packet since the last // save: @@ -89,94 +89,67 @@ // If we haven't indexed the page where the packet we're interested in starts, // begin reading pages until we have. - while(d->packetToPageMap.size() <= i) { - if(!nextPage()) { - debug("Ogg::File::packet() -- Could not find the requested packet."); - return ByteVector::null; - } + if(!readPages(i)) { + debug("Ogg::File::packet() -- Could not find the requested packet."); + return ByteVector(); } - // Start reading at the first page that contains part (or all) of this packet. - // If the last read stopped at the packet that we're interested in, don't - // reread its packet list. (This should make sequential packet reads fast.) - - uint pageIndex = d->packetToPageMap[i].front(); - if(d->currentPacketPage != d->pages[pageIndex]) { - d->currentPacketPage = d->pages[pageIndex]; - d->currentPackets = d->currentPacketPage->packets(); - } + // Look for the first page in which the requested packet starts. - // If the packet is completely contained in the first page that it's in, then - // just return it now. + List::ConstIterator it = d->pages.begin(); + while((*it)->containsPacket(i) == Page::DoesNotContainPacket) + ++it; - if(d->currentPacketPage->containsPacket(i) & Page::CompletePacket) - return d->currentPackets[i - d->currentPacketPage->firstPacketIndex()]; + // If the packet is completely contained in the first page that it's in. // If the packet is *not* completely contained in the first page that it's a // part of then that packet trails off the end of the page. Continue appending // the pages' packet data until we hit a page that either does not end with the // packet that we're fetching or where the last packet is complete. - ByteVector packet = d->currentPackets.back(); - while(d->currentPacketPage->containsPacket(i) & Page::EndsWithPacket && - !d->currentPacketPage->header()->lastPacketCompleted()) - { - pageIndex++; - if(pageIndex == d->pages.size()) { - if(!nextPage()) { - debug("Ogg::File::packet() -- Could not find the requested packet."); - return ByteVector::null; - } - } - d->currentPacketPage = d->pages[pageIndex]; - d->currentPackets = d->currentPacketPage->packets(); - packet.append(d->currentPackets.front()); + ByteVector packet = (*it)->packets()[i - (*it)->firstPacketIndex()]; + + while(nextPacketIndex(*it) <= i) { + ++it; + packet.append((*it)->packets().front()); } return packet; } -void Ogg::File::setPacket(uint i, const ByteVector &p) +void Ogg::File::setPacket(unsigned int i, const ByteVector &p) { - while(d->packetToPageMap.size() <= i) { - if(!nextPage()) { - debug("Ogg::File::setPacket() -- Could not set the requested packet."); - return; - } + if(!readPages(i)) { + debug("Ogg::File::setPacket() -- Could not set the requested packet."); + return; } - List::ConstIterator it = d->packetToPageMap[i].begin(); - for(; it != d->packetToPageMap[i].end(); ++it) - d->dirtyPages.sortedInsert(*it, true); - - d->dirtyPackets.insert(i, p); + d->dirtyPackets[i] = p; } const Ogg::PageHeader *Ogg::File::firstPageHeader() { - if(d->firstPageHeader) - return d->firstPageHeader->isValid() ? d->firstPageHeader : 0; + if(!d->firstPageHeader) { + const long firstPageHeaderOffset = find("OggS"); + if(firstPageHeaderOffset < 0) + return 0; - long firstPageHeaderOffset = find("OggS"); - - if(firstPageHeaderOffset < 0) - return 0; + d->firstPageHeader = new PageHeader(this, firstPageHeaderOffset); + } - d->firstPageHeader = new PageHeader(this, firstPageHeaderOffset); return d->firstPageHeader->isValid() ? d->firstPageHeader : 0; } const Ogg::PageHeader *Ogg::File::lastPageHeader() { - if(d->lastPageHeader) - return d->lastPageHeader->isValid() ? d->lastPageHeader : 0; + if(!d->lastPageHeader) { + const long lastPageHeaderOffset = rfind("OggS"); + if(lastPageHeaderOffset < 0) + return 0; - long lastPageHeaderOffset = rfind("OggS"); - - if(lastPageHeaderOffset < 0) - return 0; + d->lastPageHeader = new PageHeader(this, lastPageHeaderOffset); + } - d->lastPageHeader = new PageHeader(this, lastPageHeaderOffset); return d->lastPageHeader->isValid() ? d->lastPageHeader : 0; } @@ -187,18 +160,10 @@ return false; } - List pageGroup; + Map::ConstIterator it; + for(it = d->dirtyPackets.begin(); it != d->dirtyPackets.end(); ++it) + writePacket(it->first, it->second); - for(List::ConstIterator it = d->dirtyPages.begin(); it != d->dirtyPages.end(); ++it) { - if(!pageGroup.isEmpty() && pageGroup.back() + 1 != *it) { - writePageGroup(pageGroup); - pageGroup.clear(); - } - else - pageGroup.append(*it); - } - writePageGroup(pageGroup); - d->dirtyPages.clear(); d->dirtyPackets.clear(); return true; @@ -208,225 +173,141 @@ // protected members //////////////////////////////////////////////////////////////////////////////// -Ogg::File::File(FileName file) : TagLib::File(file) +Ogg::File::File(FileName file) : + TagLib::File(file), + d(new FilePrivate()) { - d = new FilePrivate; } -Ogg::File::File(IOStream *stream) : TagLib::File(stream) +Ogg::File::File(IOStream *stream) : + TagLib::File(stream), + d(new FilePrivate()) { - d = new FilePrivate; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// -bool Ogg::File::nextPage() +bool Ogg::File::readPages(unsigned int i) { - long nextPageOffset; - int currentPacket; - - if(d->pages.isEmpty()) { - currentPacket = 0; - nextPageOffset = find("OggS"); - if(nextPageOffset < 0) - return false; - } - else { - if(d->currentPage->header()->lastPageOfStream()) - return false; - - if(d->currentPage->header()->lastPacketCompleted()) - currentPacket = d->currentPage->firstPacketIndex() + d->currentPage->packetCount(); - else - currentPacket = d->currentPage->firstPacketIndex() + d->currentPage->packetCount() - 1; - - nextPageOffset = d->currentPage->fileOffset() + d->currentPage->size(); - } - - // Read the next page and add it to the page list. - - d->currentPage = new Page(this, nextPageOffset); + while(true) { + unsigned int packetIndex; + long offset; + + if(d->pages.isEmpty()) { + packetIndex = 0; + offset = find("OggS"); + if(offset < 0) + return false; + } + else { + const Page *page = d->pages.back(); + packetIndex = nextPacketIndex(page); + offset = page->fileOffset() + page->size(); + } - if(!d->currentPage->header()->isValid()) { - delete d->currentPage; - d->currentPage = 0; - return false; - } + // Enough pages have been fetched. - d->currentPage->setFirstPacketIndex(currentPacket); + if(packetIndex > i) + return true; - if(d->pages.isEmpty()) - d->streamSerialNumber = d->currentPage->header()->streamSerialNumber(); + // Read the next page and add it to the page list. - d->pages.append(d->currentPage); + Page *nextPage = new Page(this, offset); + if(!nextPage->header()->isValid()) { + delete nextPage; + return false; + } - // Loop through the packets in the page that we just read appending the - // current page number to the packet to page map for each packet. + nextPage->setFirstPacketIndex(packetIndex); + d->pages.append(nextPage); - for(uint i = 0; i < d->currentPage->packetCount(); i++) { - uint currentPacket = d->currentPage->firstPacketIndex() + i; - if(d->packetToPageMap.size() <= currentPacket) - d->packetToPageMap.push_back(List()); - d->packetToPageMap[currentPacket].append(d->pages.size() - 1); + if(nextPage->header()->lastPageOfStream()) + return false; } - - return true; } -void Ogg::File::writePageGroup(const List &thePageGroup) +void Ogg::File::writePacket(unsigned int i, const ByteVector &packet) { - if(thePageGroup.isEmpty()) + if(!readPages(i)) { + debug("Ogg::File::writePacket() -- Could not find the requested packet."); return; - - - // pages in the pageGroup and packets must be equivalent - // (originalSize and size of packets would not work together), - // therefore we sometimes have to add pages to the group - List pageGroup(thePageGroup); - while (!d->pages[pageGroup.back()]->header()->lastPacketCompleted()) { - if (d->currentPage->header()->pageSequenceNumber() == pageGroup.back()) { - if (nextPage() == false) { - debug("broken ogg file"); - return; - } - pageGroup.append(d->currentPage->header()->pageSequenceNumber()); - } else { - pageGroup.append(pageGroup.back() + 1); - } } - ByteVectorList packets; + // Look for the pages where the requested packet should belong to. - // If the first page of the group isn't dirty, append its partial content here. + List::ConstIterator it = d->pages.begin(); + while((*it)->containsPacket(i) == Page::DoesNotContainPacket) + ++it; - if(!d->dirtyPages.contains(d->pages[pageGroup.front()]->firstPacketIndex())) - packets.append(d->pages[pageGroup.front()]->packets().front()); + const Page *firstPage = *it; - int previousPacket = -1; - int originalSize = 0; + while(nextPacketIndex(*it) <= i) + ++it; - for(List::ConstIterator it = pageGroup.begin(); it != pageGroup.end(); ++it) { - uint firstPacket = d->pages[*it]->firstPacketIndex(); - uint lastPacket = firstPacket + d->pages[*it]->packetCount() - 1; + const Page *lastPage = *it; - List::ConstIterator last = --pageGroup.end(); + // Replace the requested packet and create new pages to replace the located pages. - for(uint i = firstPacket; i <= lastPacket; i++) { + ByteVectorList packets = firstPage->packets(); + packets[i - firstPage->firstPacketIndex()] = packet; - if(it == last && i == lastPacket && !d->dirtyPages.contains(i)) - packets.append(d->pages[*it]->packets().back()); - else if(int(i) != previousPacket) { - previousPacket = i; - packets.append(packet(i)); - } - } - originalSize += d->pages[*it]->size(); + if(firstPage != lastPage && lastPage->packetCount() > 2) { + ByteVectorList lastPagePackets = lastPage->packets(); + lastPagePackets.erase(lastPagePackets.begin()); + packets.append(lastPagePackets); } - const bool continued = d->pages[pageGroup.front()]->header()->firstPacketContinued(); - const bool completed = d->pages[pageGroup.back()]->header()->lastPacketCompleted(); - // TODO: This pagination method isn't accurate for what's being done here. // This should account for real possibilities like non-aligned packets and such. - List pages = Page::paginate(packets, Page::SinglePagePerGroup, - d->streamSerialNumber, pageGroup.front(), - continued, completed); + List pages = Page::paginate(packets, + Page::SinglePagePerGroup, + firstPage->header()->streamSerialNumber(), + firstPage->pageSequenceNumber(), + firstPage->header()->firstPacketContinued(), + lastPage->header()->lastPacketCompleted()); + pages.setAutoDelete(true); - List renumberedPages; + // Write the pages. - // Correct the page numbering of following pages + ByteVector data; + for(it = pages.begin(); it != pages.end(); ++it) + data.append((*it)->render()); - if (pages.back()->header()->pageSequenceNumber() != pageGroup.back()) { + const unsigned long originalOffset = firstPage->fileOffset(); + const unsigned long originalLength = lastPage->fileOffset() + lastPage->size() - originalOffset; - // TODO: change the internal data structure so that we don't need to hold the - // complete file in memory (is unavoidable at the moment) + insert(data, originalOffset, originalLength); - // read the complete stream - while(!d->currentPage->header()->lastPageOfStream()) { - if(nextPage() == false) { - debug("broken ogg file"); - break; - } - } + // Renumber the following pages if the pages have been split or merged. - // create a gap for the new pages - int numberOfNewPages = pages.back()->header()->pageSequenceNumber() - pageGroup.back(); - List::ConstIterator pageIter = d->pages.begin(); - for(int i = 0; i < pageGroup.back(); i++) { - if(pageIter != d->pages.end()) { - ++pageIter; - } - else { - debug("Ogg::File::writePageGroup() -- Page sequence is broken in original file."); - break; - } - } + const int numberOfNewPages + = pages.back()->pageSequenceNumber() - lastPage->pageSequenceNumber(); - ++pageIter; - for(; pageIter != d->pages.end(); ++pageIter) { - Ogg::Page *newPage = - (*pageIter)->getCopyWithNewPageSequenceNumber( - (*pageIter)->header()->pageSequenceNumber() + numberOfNewPages); - - ByteVector data; - data.append(newPage->render()); - insert(data, newPage->fileOffset(), data.size()); + if(numberOfNewPages != 0) { + long pageOffset = originalOffset + data.size(); - renumberedPages.append(newPage); - } - } + while(true) { + Page page(this, pageOffset); + if(!page.header()->isValid()) + break; - // insert the new data + page.setPageSequenceNumber(page.pageSequenceNumber() + numberOfNewPages); + const ByteVector data = page.render(); - ByteVector data; - for(List::ConstIterator it = pages.begin(); it != pages.end(); ++it) - data.append((*it)->render()); + seek(pageOffset + 18); + writeBlock(data.mid(18, 8)); - // The insertion algorithms could also be improve to queue and prioritize data - // on the way out. Currently it requires rewriting the file for every page - // group rather than just once; however, for tagging applications there will - // generally only be one page group, so it's not worth the time for the - // optimization at the moment. - - insert(data, d->pages[pageGroup.front()]->fileOffset(), originalSize); - - // Update the page index to include the pages we just created and to delete the - // old pages. - - // First step: Pages that contain the comment data - - for(List::ConstIterator it = pages.begin(); it != pages.end(); ++it) { - const unsigned int index = (*it)->header()->pageSequenceNumber(); - if(index < d->pages.size()) { - delete d->pages[index]; - d->pages[index] = *it; - } - else if(index == d->pages.size()) { - d->pages.append(*it); - } - else { - // oops - there's a hole in the sequence - debug("Ogg::File::writePageGroup() -- Page sequence is broken."); + if(page.header()->lastPageOfStream()) + break; + + pageOffset += page.size(); } } - // Second step: the renumbered pages + // Discard all the pages to keep them up-to-date by fetching them again. - for(List::ConstIterator it = renumberedPages.begin(); it != renumberedPages.end(); ++it) { - const unsigned int index = (*it)->header()->pageSequenceNumber(); - if(index < d->pages.size()) { - delete d->pages[index]; - d->pages[index] = *it; - } - else if(index == d->pages.size()) { - d->pages.append(*it); - } - else { - // oops - there's a hole in the sequence - debug("Ogg::File::writePageGroup() -- Page sequence is broken."); - } - } + d->pages.clear(); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/oggfile.h clementine-1.3.1-218/3rdparty/taglib/ogg/oggfile.h --- clementine-1.3.1-217/3rdparty/taglib/ogg/oggfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/oggfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -56,15 +56,15 @@ * Returns the packet contents for the i-th packet (starting from zero) * in the Ogg bitstream. * - * \warning The requires reading at least the packet header for every page + * \warning This requires reading at least the packet header for every page * up to the requested page. */ - ByteVector packet(uint i); + ByteVector packet(unsigned int i); /*! * Sets the packet with index \a i to the value \a p. */ - void setPacket(uint i, const ByteVector &p); + void setPacket(unsigned int i, const ByteVector &p); /*! * Returns a pointer to the PageHeader for the first page in the stream or @@ -107,10 +107,15 @@ File &operator=(const File &); /*! - * Reads the next page and updates the internal "current page" pointer. + * Reads the pages from the beginning of the file until enough to compose + * the requested packet. */ - bool nextPage(); - void writePageGroup(const List &group); + bool readPages(unsigned int i); + + /*! + * Writes the requested packet to the file. + */ + void writePacket(unsigned int i, const ByteVector &packet); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/oggpage.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/oggpage.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/oggpage.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/oggpage.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,6 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include + #include #include @@ -38,22 +40,11 @@ PagePrivate(File *f = 0, long pageOffset = -1) : file(f), fileOffset(pageOffset), - packetOffset(0), header(f, pageOffset), - firstPacketIndex(-1) - { - if(file) { - packetOffset = fileOffset + header.size(); - packetSizes = header.packetSizes(); - dataSize = header.dataSize(); - } - } + firstPacketIndex(-1) {} File *file; long fileOffset; - long packetOffset; - int dataSize; - List packetSizes; PageHeader header; int firstPacketIndex; ByteVectorList packets; @@ -63,9 +54,9 @@ // public members //////////////////////////////////////////////////////////////////////////////// -Ogg::Page::Page(Ogg::File *file, long pageOffset) +Ogg::Page::Page(Ogg::File *file, long pageOffset) : + d(new PagePrivate(file, pageOffset)) { - d = new PagePrivate(file, pageOffset); } Ogg::Page::~Page() @@ -83,6 +74,16 @@ return &d->header; } +int Ogg::Page::pageSequenceNumber() const +{ + return d->header.pageSequenceNumber(); +} + +void Ogg::Page::setPageSequenceNumber(int sequenceNumber) +{ + d->header.setPageSequenceNumber(sequenceNumber); +} + int Ogg::Page::firstPacketIndex() const { return d->firstPacketIndex; @@ -95,7 +96,7 @@ Ogg::Page::ContainsPacketFlags Ogg::Page::containsPacket(int index) const { - int lastPacketIndex = d->firstPacketIndex + packetCount() - 1; + const int lastPacketIndex = d->firstPacketIndex + packetCount() - 1; if(index < d->firstPacketIndex || index > lastPacketIndex) return DoesNotContainPacket; @@ -131,7 +132,7 @@ return flags; } -TagLib::uint Ogg::Page::packetCount() const +unsigned int Ogg::Page::packetCount() const { return d->header.packetSizes().size(); } @@ -145,7 +146,7 @@ if(d->file && d->header.isValid()) { - d->file->seek(d->packetOffset); + d->file->seek(d->fileOffset + d->header.size()); List packetSizes = d->header.packetSizes(); @@ -172,8 +173,8 @@ if(d->packets.isEmpty()) { if(d->file) { - d->file->seek(d->packetOffset); - data.append(d->file->readBlock(d->dataSize)); + d->file->seek(d->fileOffset + d->header.size()); + data.append(d->file->readBlock(d->header.dataSize())); } else debug("Ogg::Page::render() -- this page is empty!"); @@ -188,121 +189,90 @@ // the entire page with the 4 bytes reserved for the checksum zeroed and then // inserted in bytes 22-25 of the page header. - ByteVector checksum = ByteVector::fromUInt(data.checksum(), false); - for(int i = 0; i < 4; i++) - data[i + 22] = checksum[i]; + const ByteVector checksum = ByteVector::fromUInt(data.checksum(), false); + std::copy(checksum.begin(), checksum.end(), data.begin() + 22); return data; } List Ogg::Page::paginate(const ByteVectorList &packets, PaginationStrategy strategy, - uint streamSerialNumber, + unsigned int streamSerialNumber, int firstPage, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket) { - List l; + // SplitSize must be a multiple of 255 in order to get the lacing values right + // create pages of about 8KB each + + static const unsigned int SplitSize = 32 * 255; + + // Force repagination if the packets are too large for a page. + + if(strategy != Repaginate) { - int totalSize = 0; + size_t totalSize = packets.size(); + for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) + totalSize += it->size(); - for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) - totalSize += (*it).size(); + if(totalSize > 255 * 255) + strategy = Repaginate; + } + + List l; // Handle creation of multiple pages with appropriate pagination. - if(strategy == Repaginate || totalSize + packets.size() > 255 * 255) { - // SPLITSIZE must be a multiple of 255 in order to get the lacing values right - // create pages of about 8KB each -#define SPLITSIZE (32*255) + if(strategy == Repaginate) { - int pageIndex = 0; + int pageIndex = firstPage; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { - bool continued = false; + + const bool lastPacketInList = (it == --packets.end()); // mark very first packet? - if(firstPacketContinued && it==packets.begin()) { - continued = true; - } - // append to buf - ByteVector packetBuf; - packetBuf.append(*it); - - while(packetBuf.size() > SPLITSIZE) { - // output a Page - ByteVector packetForOnePage; - packetForOnePage.resize(SPLITSIZE); - std::copy(packetBuf.begin(), packetBuf.begin() + SPLITSIZE, packetForOnePage.begin()); + bool continued = (firstPacketContinued && it == packets.begin()); + unsigned int pos = 0; + + while(pos < it->size()) { + + const bool lastSplit = (pos + SplitSize >= it->size()); ByteVectorList packetList; - packetList.append(packetForOnePage); - Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, false, false); - l.append(p); + packetList.append(it->mid(pos, SplitSize)); + l.append(new Page(packetList, + streamSerialNumber, + pageIndex, + continued, + lastSplit && (lastPacketInList ? lastPacketCompleted : true), + lastSplit && (containsLastPacket && lastPacketInList))); pageIndex++; continued = true; - packetBuf = packetBuf.mid(SPLITSIZE); - } - ByteVectorList::ConstIterator jt = it; - ++jt; - bool lastPacketInList = (jt == packets.end()); - - // output a page for the rest (we output one packet per page, so this one should be completed) - ByteVectorList packetList; - packetList.append(packetBuf); - - bool isVeryLastPacket = false; - if(containsLastPacket) { - // mark the very last output page as last of stream - ByteVectorList::ConstIterator jt = it; - ++jt; - if(jt == packets.end()) { - isVeryLastPacket = true; - } + pos += SplitSize; } - - Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, - lastPacketInList ? lastPacketCompleted : true, - isVeryLastPacket); - pageIndex++; - - l.append(p); } } else { - Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued, - lastPacketCompleted, containsLastPacket); - l.append(p); + l.append(new Page(packets, + streamSerialNumber, + firstPage, + firstPacketContinued, + lastPacketCompleted, + containsLastPacket)); } return l; } -Ogg::Page* Ogg::Page::getCopyWithNewPageSequenceNumber(int sequenceNumber) +Ogg::Page* Ogg::Page::getCopyWithNewPageSequenceNumber(int /*sequenceNumber*/) { - Page *pResultPage = NULL; - - // TODO: a copy constructor would be helpful - - if(d->file == 0) { - pResultPage = new Page( - d->packets, - d->header.streamSerialNumber(), - sequenceNumber, - d->header.firstPacketContinued(), - d->header.lastPacketCompleted(), - d->header.lastPageOfStream()); - } - else - { - pResultPage = new Page(d->file, d->fileOffset); - pResultPage->d->header.setPageSequenceNumber(sequenceNumber); - } - return pResultPage; + debug("Ogg::Page::getCopyWithNewPageSequenceNumber() -- This function is obsolete. Returning null."); + return 0; } //////////////////////////////////////////////////////////////////////////////// @@ -310,17 +280,13 @@ //////////////////////////////////////////////////////////////////////////////// Ogg::Page::Page(const ByteVectorList &packets, - uint streamSerialNumber, + unsigned int streamSerialNumber, int pageNumber, bool firstPacketContinued, bool lastPacketCompleted, - bool containsLastPacket) + bool containsLastPacket) : + d(new PagePrivate()) { - d = new PagePrivate; - - ByteVector data; - List packetSizes; - d->header.setFirstPageOfStream(pageNumber == 0 && !firstPacketContinued); d->header.setLastPageOfStream(containsLastPacket); d->header.setFirstPacketContinued(firstPacketContinued); @@ -330,6 +296,9 @@ // Build a page from the list of packets. + ByteVector data; + List packetSizes; + for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { packetSizes.append((*it).size()); data.append(*it); @@ -337,4 +306,3 @@ d->packets = packets; d->header.setPacketSizes(packetSizes); } - diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/oggpage.h clementine-1.3.1-218/3rdparty/taglib/ogg/oggpage.h --- clementine-1.3.1-217/3rdparty/taglib/ogg/oggpage.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/oggpage.h 2016-07-19 15:25:23.000000000 +0000 @@ -71,10 +71,27 @@ const PageHeader *header() const; /*! + * Returns the index of the page within the Ogg stream. This helps make it + * possible to determine if pages have been lost. + * + * \see setPageSequenceNumber() + */ + int pageSequenceNumber() const; + + /*! + * Sets the page's position in the stream to \a sequenceNumber. + * + * \see pageSequenceNumber() + */ + void setPageSequenceNumber(int sequenceNumber); + + /*! * Returns a copy of the page with \a sequenceNumber set as sequence number. * * \see header() * \see PageHeader::setPageSequenceNumber() + * + * \deprecated Always returns null. */ Page* getCopyWithNewPageSequenceNumber(int sequenceNumber); @@ -121,7 +138,7 @@ /*! * Returns the number of packets (whole or partial) in this page. */ - uint packetCount() const; + unsigned int packetCount() const; /*! * Returns a list of the packets in this page. @@ -181,7 +198,7 @@ */ static List paginate(const ByteVectorList &packets, PaginationStrategy strategy, - uint streamSerialNumber, + unsigned int streamSerialNumber, int firstPage, bool firstPacketContinued = false, bool lastPacketCompleted = true, @@ -193,7 +210,7 @@ * for each page will be set to \a pageNumber. */ Page(const ByteVectorList &packets, - uint streamSerialNumber, + unsigned int streamSerialNumber, int pageNumber, bool firstPacketContinued = false, bool lastPacketCompleted = true, diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/oggpageheader.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/oggpageheader.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/oggpageheader.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/oggpageheader.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,8 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include - #include #include @@ -39,9 +37,7 @@ class Ogg::PageHeader::PageHeaderPrivate { public: - PageHeaderPrivate(File *f, long pageOffset) : - file(f), - fileOffset(pageOffset), + PageHeaderPrivate() : isValid(false), firstPacketContinued(false), lastPacketCompleted(false), @@ -51,11 +47,8 @@ streamSerialNumber(0), pageSequenceNumber(-1), size(0), - dataSize(0) - {} + dataSize(0) {} - File *file; - long fileOffset; bool isValid; List packetSizes; bool firstPacketContinued; @@ -63,7 +56,7 @@ bool firstPageOfStream; bool lastPageOfStream; long long absoluteGranularPosition; - uint streamSerialNumber; + unsigned int streamSerialNumber; int pageSequenceNumber; int size; int dataSize; @@ -73,11 +66,11 @@ // public members //////////////////////////////////////////////////////////////////////////////// -Ogg::PageHeader::PageHeader(Ogg::File *file, long pageOffset) +Ogg::PageHeader::PageHeader(Ogg::File *file, long pageOffset) : + d(new PageHeaderPrivate()) { - d = new PageHeaderPrivate(file, pageOffset); if(file && pageOffset >= 0) - read(); + read(file, pageOffset); } Ogg::PageHeader::~PageHeader() @@ -160,12 +153,12 @@ d->pageSequenceNumber = sequenceNumber; } -TagLib::uint Ogg::PageHeader::streamSerialNumber() const +unsigned int Ogg::PageHeader::streamSerialNumber() const { return d->streamSerialNumber; } -void Ogg::PageHeader::setStreamSerialNumber(uint n) +void Ogg::PageHeader::setStreamSerialNumber(unsigned int n) { d->streamSerialNumber = n; } @@ -184,7 +177,7 @@ { ByteVector data; - // capture patern + // capture pattern data.append("OggS"); @@ -222,7 +215,7 @@ ByteVector pageSegments = lacingValues(); - data.append(char(uchar(pageSegments.size()))); + data.append(static_cast(pageSegments.size())); data.append(pageSegments); return data; @@ -232,14 +225,14 @@ // private members //////////////////////////////////////////////////////////////////////////////// -void Ogg::PageHeader::read() +void Ogg::PageHeader::read(Ogg::File *file, long pageOffset) { - d->file->seek(d->fileOffset); + file->seek(pageOffset); // An Ogg page header is at least 27 bytes, so we'll go ahead and read that // much and then get the rest when we're ready for it. - ByteVector data = d->file->readBlock(27); + const ByteVector data = file->readBlock(27); // Sanity check -- make sure that we were in fact able to read as much data as // we asked for and that the page begins with "OggS". @@ -249,11 +242,11 @@ return; } - std::bitset<8> flags(data[5]); + const std::bitset<8> flags(data[5]); d->firstPacketContinued = flags.test(0); - d->firstPageOfStream = flags.test(1); - d->lastPageOfStream = flags.test(2); + d->firstPageOfStream = flags.test(1); + d->lastPageOfStream = flags.test(2); d->absoluteGranularPosition = data.toLongLong(6, false); d->streamSerialNumber = data.toUInt(14, false); @@ -263,9 +256,9 @@ // length portion of the page header. After reading the number of page // segments we'll then read in the corresponding data for this count. - int pageSegmentCount = uchar(data[26]); + int pageSegmentCount = static_cast(data[26]); - ByteVector pageSegments = d->file->readBlock(pageSegmentCount); + const ByteVector pageSegments = file->readBlock(pageSegmentCount); // Another sanity check. @@ -279,10 +272,10 @@ int packetSize = 0; for(int i = 0; i < pageSegmentCount; i++) { - d->dataSize += uchar(pageSegments[i]); - packetSize += uchar(pageSegments[i]); + d->dataSize += static_cast(pageSegments[i]); + packetSize += static_cast(pageSegments[i]); - if(uchar(pageSegments[i]) < 255) { + if(static_cast(pageSegments[i]) < 255) { d->packetSizes.append(packetSize); packetSize = 0; } @@ -302,21 +295,17 @@ { ByteVector data; - List sizes = d->packetSizes; - for(List::ConstIterator it = sizes.begin(); it != sizes.end(); ++it) { + for(List::ConstIterator it = d->packetSizes.begin(); it != d->packetSizes.end(); ++it) { // The size of a packet in an Ogg page is indicated by a series of "lacing // values" where the sum of the values is the packet size in bytes. Each of // these values is a byte. A value of less than 255 (0xff) indicates the end // of the packet. - div_t n = div(*it, 255); - - for(int i = 0; i < n.quot; i++) - data.append(char(uchar(255))); + data.resize(data.size() + (*it / 255), '\xff'); - if(it != --sizes.end() || d->lastPacketCompleted) - data.append(char(uchar(n.rem))); + if(it != --d->packetSizes.end() || d->lastPacketCompleted) + data.append(static_cast(*it % 255)); } return data; diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/oggpageheader.h clementine-1.3.1-218/3rdparty/taglib/ogg/oggpageheader.h --- clementine-1.3.1-217/3rdparty/taglib/ogg/oggpageheader.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/oggpageheader.h 2016-07-19 15:25:23.000000000 +0000 @@ -169,7 +169,7 @@ * * \see setStreamSerialNumber() */ - uint streamSerialNumber() const; + unsigned int streamSerialNumber() const; /*! * Every Ogg logical stream is given a random serial number which is common @@ -179,7 +179,7 @@ * * \see streamSerialNumber() */ - void setStreamSerialNumber(uint n); + void setStreamSerialNumber(unsigned int n); /*! * Returns the index of the page within the Ogg stream. This helps make it @@ -219,7 +219,7 @@ PageHeader(const PageHeader &); PageHeader &operator=(const PageHeader &); - void read(); + void read(Ogg::File *file, long pageOffset); ByteVector lacingValues() const; class PageHeaderPrivate; diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/opus/opusproperties.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/opus/opusproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/opus/opusproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/opus/opusproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -127,18 +127,18 @@ const ByteVector data = file->packet(0); // *Magic Signature* - uint pos = 8; + unsigned int pos = 8; // *Version* (8 bits, unsigned) - d->opusVersion = uchar(data.at(pos)); + d->opusVersion = static_cast(data.at(pos)); pos += 1; // *Output Channel Count* 'C' (8 bits, unsigned) - d->channels = uchar(data.at(pos)); + d->channels = static_cast(data.at(pos)); pos += 1; // *Pre-skip* (16 bits, unsigned, little endian) - const ushort preSkip = data.toUShort(pos, false); + const unsigned short preSkip = data.toUShort(pos, false); pos += 2; // *Input Sample Rate* (32 bits, unsigned, little endian) diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/speex/speexproperties.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/speex/speexproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/speex/speexproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/speex/speexproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -131,7 +131,7 @@ return; } - uint pos = 28; + unsigned int pos = 28; // speex_version_id; /**< Version for Speex (for checking compatibility) */ d->speexVersion = data.toUInt(pos, false); diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -144,7 +144,7 @@ return; } - uint pos = 0; + unsigned int pos = 0; if(data.mid(pos, 7) != vorbisSetupHeaderID) { debug("Vorbis::Properties::read() -- invalid Vorbis identification header"); @@ -156,7 +156,7 @@ d->vorbisVersion = data.toUInt(pos, false); pos += 4; - d->channels = uchar(data[pos]); + d->channels = static_cast(data[pos]); pos += 1; d->sampleRate = data.toUInt(pos, false); diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/xiphcomment.cpp clementine-1.3.1-218/3rdparty/taglib/ogg/xiphcomment.cpp --- clementine-1.3.1-217/3rdparty/taglib/ogg/xiphcomment.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/xiphcomment.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -26,31 +26,50 @@ #include #include +#include #include #include using namespace TagLib; +namespace +{ + typedef Ogg::FieldListMap::Iterator FieldIterator; + typedef Ogg::FieldListMap::ConstIterator FieldConstIterator; + + typedef List PictureList; + typedef PictureList::Iterator PictureIterator; + typedef PictureList::Iterator PictureConstIterator; +} + class Ogg::XiphComment::XiphCommentPrivate { public: + XiphCommentPrivate() + { + pictureList.setAutoDelete(true); + } + FieldListMap fieldListMap; String vendorID; String commentField; + PictureList pictureList; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -Ogg::XiphComment::XiphComment() : TagLib::Tag() +Ogg::XiphComment::XiphComment() : + TagLib::Tag(), + d(new XiphCommentPrivate()) { - d = new XiphCommentPrivate; } -Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag() +Ogg::XiphComment::XiphComment(const ByteVector &data) : + TagLib::Tag(), + d(new XiphCommentPrivate()) { - d = new XiphCommentPrivate; parse(data); } @@ -62,21 +81,21 @@ String Ogg::XiphComment::title() const { if(d->fieldListMap["TITLE"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["TITLE"].toString(); } String Ogg::XiphComment::artist() const { if(d->fieldListMap["ARTIST"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["ARTIST"].toString(); } String Ogg::XiphComment::album() const { if(d->fieldListMap["ALBUM"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["ALBUM"].toString(); } @@ -92,17 +111,17 @@ return d->fieldListMap["COMMENT"].toString(); } - return String::null; + return String(); } String Ogg::XiphComment::genre() const { if(d->fieldListMap["GENRE"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["GENRE"].toString(); } -TagLib::uint Ogg::XiphComment::year() const +unsigned int Ogg::XiphComment::year() const { if(!d->fieldListMap["DATE"].isEmpty()) return d->fieldListMap["DATE"].front().toInt(); @@ -111,7 +130,7 @@ return 0; } -TagLib::uint Ogg::XiphComment::track() const +unsigned int Ogg::XiphComment::track() const { if(!d->fieldListMap["TRACKNUMBER"].isEmpty()) return d->fieldListMap["TRACKNUMBER"].front().toInt(); @@ -137,7 +156,14 @@ void Ogg::XiphComment::setComment(const String &s) { - addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s); + if(d->commentField.isEmpty()) { + if(!d->fieldListMap["DESCRIPTION"].isEmpty()) + d->commentField = "DESCRIPTION"; + else + d->commentField = "COMMENT"; + } + + addField(d->commentField, s); } void Ogg::XiphComment::setGenre(const String &s) @@ -145,42 +171,43 @@ addField("GENRE", s); } -void Ogg::XiphComment::setYear(uint i) +void Ogg::XiphComment::setYear(unsigned int i) { - removeField("YEAR"); + removeFields("YEAR"); if(i == 0) - removeField("DATE"); + removeFields("DATE"); else addField("DATE", String::number(i)); } -void Ogg::XiphComment::setTrack(uint i) +void Ogg::XiphComment::setTrack(unsigned int i) { - removeField("TRACKNUM"); + removeFields("TRACKNUM"); if(i == 0) - removeField("TRACKNUMBER"); + removeFields("TRACKNUMBER"); else addField("TRACKNUMBER", String::number(i)); } bool Ogg::XiphComment::isEmpty() const { - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for(; it != d->fieldListMap.end(); ++it) + for(FieldConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) { if(!(*it).second.isEmpty()) return false; + } return true; } -TagLib::uint Ogg::XiphComment::fieldCount() const +unsigned int Ogg::XiphComment::fieldCount() const { - uint count = 0; + unsigned int count = 0; - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for(; it != d->fieldListMap.end(); ++it) + for(FieldConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) count += (*it).second.size(); + count += d->pictureList.size(); + return count; } @@ -198,12 +225,12 @@ { // check which keys are to be deleted StringList toRemove; - for(FieldListMap::ConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) + for(FieldConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) if (!properties.contains(it->first)) toRemove.append(it->first); for(StringList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it) - removeField(*it); + removeFields(*it); // now go through keys in \a properties and check that the values match those in the xiph comment PropertyMap invalid; @@ -214,9 +241,9 @@ invalid.insert(it->first, it->second); else if(!d->fieldListMap.contains(it->first) || !(it->second == d->fieldListMap[it->first])) { const StringList &sl = it->second; - if(sl.size() == 0) + if(sl.isEmpty()) // zero size string list -> remove the tag with all values - removeField(it->first); + removeFields(it->first); else { // replace all strings in the list for the tag StringList::ConstIterator valueIterator = sl.begin(); @@ -249,7 +276,7 @@ void Ogg::XiphComment::addField(const String &key, const String &value, bool replace) { if(replace) - removeField(key.upper()); + removeFields(key.upper()); if(!key.isEmpty() && !value.isEmpty()) d->fieldListMap[key.upper()].append(value); @@ -257,22 +284,61 @@ void Ogg::XiphComment::removeField(const String &key, const String &value) { - if(!value.isNull()) { - StringList::Iterator it = d->fieldListMap[key].begin(); - while(it != d->fieldListMap[key].end()) { - if(value == *it) - it = d->fieldListMap[key].erase(it); - else - it++; - } - } + if(!value.isNull()) + removeFields(key, value); else - d->fieldListMap.erase(key); + removeFields(key); +} + +void Ogg::XiphComment::removeFields(const String &key) +{ + d->fieldListMap.erase(key.upper()); +} + +void Ogg::XiphComment::removeFields(const String &key, const String &value) +{ + StringList &fields = d->fieldListMap[key.upper()]; + for(StringList::Iterator it = fields.begin(); it != fields.end(); ) { + if(*it == value) + it = fields.erase(it); + else + ++it; + } +} + +void Ogg::XiphComment::removeAllFields() +{ + d->fieldListMap.clear(); } bool Ogg::XiphComment::contains(const String &key) const { - return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty(); + return !d->fieldListMap[key.upper()].isEmpty(); +} + +void Ogg::XiphComment::removePicture(FLAC::Picture *picture, bool del) +{ + PictureIterator it = d->pictureList.find(picture); + if(it != d->pictureList.end()) + d->pictureList.erase(it); + + if(del) + delete picture; +} + +void Ogg::XiphComment::removeAllPictures() +{ + d->pictureList.clear(); +} + +void Ogg::XiphComment::addPicture(FLAC::Picture * picture) +{ + d->pictureList.append(picture); +} + +List Ogg::XiphComment::pictureList() +{ + return d->pictureList; } ByteVector Ogg::XiphComment::render() const @@ -321,6 +387,13 @@ } } + for(PictureConstIterator it = d->pictureList.begin(); it != d->pictureList.end(); ++it) { + ByteVector picture = (*it)->render().toBase64(); + data.append(ByteVector::fromUInt(picture.size() + 23, false)); + data.append("METADATA_BLOCK_PICTURE="); + data.append(picture); + } + // Append the "framing bit". if(addFramingBit) @@ -338,9 +411,9 @@ // The first thing in the comment data is the vendor ID length, followed by a // UTF8 string with the vendor ID. - uint pos = 0; + unsigned int pos = 0; - const uint vendorLength = data.toUInt(0, false); + const unsigned int vendorLength = data.toUInt(0, false); pos += 4; d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); @@ -348,35 +421,100 @@ // Next the number of fields in the comment vector. - const uint commentFields = data.toUInt(pos, false); + const unsigned int commentFields = data.toUInt(pos, false); pos += 4; if(commentFields > (data.size() - 8) / 4) { return; } - for(uint i = 0; i < commentFields; i++) { + for(unsigned int i = 0; i < commentFields; i++) { // Each comment field is in the format "KEY=value" in a UTF8 string and has // 4 bytes before the text starts that gives the length. - const uint commentLength = data.toUInt(pos, false); + const unsigned int commentLength = data.toUInt(pos, false); pos += 4; - String comment = String(data.mid(pos, commentLength), String::UTF8); + ByteVector entry = data.mid(pos, commentLength); + pos += commentLength; - if(pos > data.size()) { + + // Don't go past data end + if(pos > data.size()) break; + + // Handle Pictures separately + if(entry.startsWith("METADATA_BLOCK_PICTURE=")) { + + // We need base64 encoded data including padding + if((entry.size() - 23) > 3 && ((entry.size() - 23) % 4) == 0) { + + // Decode base64 picture data + ByteVector picturedata = ByteVector::fromBase64(entry.mid(23)); + if(picturedata.size()) { + + // Decode Flac Picture + FLAC::Picture * picture = new FLAC::Picture(); + if(picture->parse(picturedata)) { + + d->pictureList.append(picture); + + // continue to next field + continue; + } + else { + delete picture; + debug("Failed to decode FlacPicture block"); + } + } + else { + debug("Failed to decode base64 encoded data"); + } + } + else { + debug("Invalid base64 encoded data"); + } } - int commentSeparatorPosition = comment.find("="); - if(commentSeparatorPosition == -1) { - break; + // Handle old picture standard + if(entry.startsWith("COVERART=")) { + + if((entry.size() - 9) > 3 && ((entry.size() - 9) % 4) == 0) { + + // Decode base64 picture data + ByteVector picturedata = ByteVector::fromBase64(entry.mid(9)); + if (picturedata.size()) { + + // Assume it's some type of image file + FLAC::Picture * picture = new FLAC::Picture(); + picture->setData(picturedata); + picture->setMimeType("image/"); + picture->setType(FLAC::Picture::Other); + d->pictureList.append(picture); + + // continue to next field + continue; + } + else { + debug("Failed to decode base64 encoded data"); + } + } + else { + debug("Invalid base64 encoded data"); + } } - String key = comment.substr(0, commentSeparatorPosition); - String value = comment.substr(commentSeparatorPosition + 1); + // Check for field separator + int sep = entry.find('='); + if(sep < 1) { + debug("Discarding invalid comment field."); + continue; + } + // Parse key and value + String key = String(entry.mid(0, sep), String::UTF8); + String value = String(entry.mid(sep + 1), String::UTF8); addField(key, value, false); } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/ogg/xiphcomment.h clementine-1.3.1-218/3rdparty/taglib/ogg/xiphcomment.h --- clementine-1.3.1-217/3rdparty/taglib/ogg/xiphcomment.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/ogg/xiphcomment.h 2016-07-19 15:25:23.000000000 +0000 @@ -32,6 +32,7 @@ #include "tstring.h" #include "tstringlist.h" #include "tbytevector.h" +#include "flacpicture.h" #include "taglib_export.h" namespace TagLib { @@ -84,23 +85,23 @@ virtual String album() const; virtual String comment() const; virtual String genre() const; - virtual uint year() const; - virtual uint track() const; + virtual unsigned int year() const; + virtual unsigned int track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); - virtual void setYear(uint i); - virtual void setTrack(uint i); + virtual void setYear(unsigned int i); + virtual void setTrack(unsigned int i); virtual bool isEmpty() const; /*! * Returns the number of fields present in the comment. */ - uint fieldCount() const; + unsigned int fieldCount() const; /*! * Returns a reference to the map of field lists. Because Xiph comments @@ -181,10 +182,34 @@ /*! * Remove the field specified by \a key with the data \a value. If * \a value is null, all of the fields with the given key will be removed. + * + * \deprecated Using this method may lead to a linkage error. */ + // BIC: remove and merge with below void removeField(const String &key, const String &value = String::null); /*! + * Remove all the fields specified by \a key. + * + * \see removeAllFields() + */ + void removeFields(const String &key); + + /*! + * Remove all the fields specified by \a key with the data \a value. + * + * \see removeAllFields() + */ + void removeFields(const String &key, const String &value); + + /*! + * Remove all the fields in the comment. + * + * \see removeFields() + */ + void removeAllFields(); + + /*! * Returns true if the field is contained within the comment. * * \note This is safer than checking for membership in the FieldListMap. @@ -205,6 +230,31 @@ */ ByteVector render(bool addFramingBit) const; + + /*! + * Returns a list of pictures attached to the xiph comment. + */ + List pictureList(); + + /*! + * Removes an 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(FLAC::Picture *picture, bool del = true); + + /*! + * Remove all pictures. + */ + void removeAllPictures(); + + /*! + * Add a new picture to the comment block. The comment block takes ownership of the + * picture and will handle freeing its memory. + * + * \note The file will be saved only after calling save(). + */ + void addPicture(FLAC::Picture *picture); + protected: /*! * Reads the tag from the file specified in the constructor and fills the diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/aiff/aifffile.cpp clementine-1.3.1-218/3rdparty/taglib/riff/aiff/aifffile.cpp --- clementine-1.3.1-217/3rdparty/taglib/riff/aiff/aifffile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/aiff/aifffile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -39,7 +39,6 @@ FilePrivate() : properties(0), tag(0), - tagChunkID("ID3 "), hasID3v2(false) {} ~FilePrivate() @@ -50,7 +49,6 @@ Properties *properties; ID3v2::Tag *tag; - ByteVector tagChunkID; bool hasID3v2; }; @@ -117,8 +115,16 @@ return false; } - setChunkData(d->tagChunkID, d->tag->render()); - d->hasID3v2 = true; + if(d->hasID3v2) { + removeChunk("ID3 "); + removeChunk("id3 "); + d->hasID3v2 = false; + } + + if(tag() && !tag()->isEmpty()) { + setChunkData("ID3 ", d->tag->render()); + d->hasID3v2 = true; + } return true; } @@ -134,12 +140,11 @@ void RIFF::AIFF::File::read(bool readProperties) { - for(uint i = 0; i < chunkCount(); ++i) { + for(unsigned int i = 0; i < chunkCount(); ++i) { const ByteVector name = chunkName(i); if(name == "ID3 " || name == "id3 ") { if(!d->tag) { d->tag = new ID3v2::Tag(this, chunkOffset(i)); - d->tagChunkID = name; d->hasID3v2 = true; } else { diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/aiff/aiffproperties.cpp clementine-1.3.1-218/3rdparty/taglib/riff/aiff/aiffproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/riff/aiff/aiffproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/aiff/aiffproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -50,7 +50,7 @@ ByteVector compressionType; String compressionName; - uint sampleFrames; + unsigned int sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// @@ -116,7 +116,7 @@ return bitsPerSample(); } -TagLib::uint RIFF::AIFF::Properties::sampleFrames() const +unsigned int RIFF::AIFF::Properties::sampleFrames() const { return d->sampleFrames; } @@ -143,8 +143,8 @@ void RIFF::AIFF::Properties::read(File *file) { ByteVector data; - uint streamLength = 0; - for(uint i = 0; i < file->chunkCount(); i++) { + unsigned int streamLength = 0; + for(unsigned int i = 0; i < file->chunkCount(); i++) { const ByteVector name = file->chunkName(i); if(name == "COMM") { if(data.isEmpty()) @@ -179,13 +179,14 @@ d->sampleRate = static_cast(sampleRate + 0.5); if(d->sampleFrames > 0 && d->sampleRate > 0) { - const double length = d->sampleFrames * 1000.0 / d->sampleRate; + const double length = d->sampleFrames * 1000.0 / sampleRate; d->length = static_cast(length + 0.5); d->bitrate = static_cast(streamLength * 8.0 / length + 0.5); } if(data.size() >= 23) { d->compressionType = data.mid(18, 4); - d->compressionName = String(data.mid(23, static_cast(data[22])), String::Latin1); + d->compressionName + = String(data.mid(23, static_cast(data[22])), String::Latin1); } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/aiff/aiffproperties.h clementine-1.3.1-218/3rdparty/taglib/riff/aiff/aiffproperties.h --- clementine-1.3.1-217/3rdparty/taglib/riff/aiff/aiffproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/aiff/aiffproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -124,7 +124,7 @@ /*! * Returns the number of sample frames */ - uint sampleFrames() const; + unsigned int sampleFrames() const; /*! * Returns true if the file is in AIFF-C format, false if AIFF format. diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/rifffile.cpp clementine-1.3.1-218/3rdparty/taglib/riff/rifffile.cpp --- clementine-1.3.1-217/3rdparty/taglib/riff/rifffile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/rifffile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,37 +23,38 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include +#include + #include #include #include #include "rifffile.h" -#include -#include +#include "riffutils.h" using namespace TagLib; struct Chunk { - ByteVector name; - TagLib::uint offset; - TagLib::uint size; - char padding; + ByteVector name; + unsigned int offset; + unsigned int size; + unsigned int padding; }; class RIFF::File::FilePrivate { public: - FilePrivate() : - endianness(BigEndian), - size(0) - { + FilePrivate(Endianness endianness) : + endianness(endianness), + size(0), + sizeOffset(0) {} - } - Endianness endianness; - ByteVector type; - TagLib::uint size; - ByteVector format; + const Endianness endianness; + + unsigned int size; + long sizeOffset; std::vector chunks; }; @@ -71,84 +72,112 @@ // protected members //////////////////////////////////////////////////////////////////////////////// -RIFF::File::File(FileName file, Endianness endianness) : TagLib::File(file) +RIFF::File::File(FileName file, Endianness endianness) : + TagLib::File(file), + d(new FilePrivate(endianness)) { - d = new FilePrivate; - d->endianness = endianness; - if(isOpen()) read(); } -RIFF::File::File(IOStream *stream, Endianness endianness) : TagLib::File(stream) +RIFF::File::File(IOStream *stream, Endianness endianness) : + TagLib::File(stream), + d(new FilePrivate(endianness)) { - d = new FilePrivate; - d->endianness = endianness; - if(isOpen()) read(); } -TagLib::uint RIFF::File::riffSize() const +unsigned int RIFF::File::riffSize() const { return d->size; } -TagLib::uint RIFF::File::chunkCount() const +unsigned int RIFF::File::chunkCount() const { return d->chunks.size(); } -TagLib::uint RIFF::File::chunkDataSize(uint i) const +unsigned int RIFF::File::chunkDataSize(unsigned int i) const { + if(i >= d->chunks.size()) { + debug("RIFF::File::chunkPadding() - Index out of range. Returning 0."); + return 0; + } + return d->chunks[i].size; } -TagLib::uint RIFF::File::chunkOffset(uint i) const +unsigned int RIFF::File::chunkOffset(unsigned int i) const { + if(i >= d->chunks.size()) { + debug("RIFF::File::chunkPadding() - Index out of range. Returning 0."); + return 0; + } + return d->chunks[i].offset; } -TagLib::uint RIFF::File::chunkPadding(uint i) const +unsigned int RIFF::File::chunkPadding(unsigned int i) const { + if(i >= d->chunks.size()) { + debug("RIFF::File::chunkPadding() - Index out of range. Returning 0."); + return 0; + } + return d->chunks[i].padding; } -ByteVector RIFF::File::chunkName(uint i) const +ByteVector RIFF::File::chunkName(unsigned int i) const { - if(i >= chunkCount()) - return ByteVector::null; + if(i >= d->chunks.size()) { + debug("RIFF::File::chunkName() - Index out of range. Returning an empty vector."); + return ByteVector(); + } return d->chunks[i].name; } -ByteVector RIFF::File::chunkData(uint i) +ByteVector RIFF::File::chunkData(unsigned int i) { - if(i >= chunkCount()) - return ByteVector::null; + if(i >= d->chunks.size()) { + debug("RIFF::File::chunkData() - Index out of range. Returning an empty vector."); + return ByteVector(); + } seek(d->chunks[i].offset); return readBlock(d->chunks[i].size); } -void RIFF::File::setChunkData(uint i, const ByteVector &data) +void RIFF::File::setChunkData(unsigned int i, const ByteVector &data) { - // First we update the global size - - d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding); - insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4); + if(i >= d->chunks.size()) { + debug("RIFF::File::setChunkData() - Index out of range."); + return; + } // Now update the specific chunk - writeChunk(chunkName(i), data, d->chunks[i].offset - 8, d->chunks[i].size + d->chunks[i].padding + 8); + std::vector::iterator it = d->chunks.begin(); + std::advance(it, i); + + const int originalSize = it->size + it->padding; + + writeChunk(it->name, data, it->offset - 8, it->size + it->padding + 8); - d->chunks[i].size = data.size(); - d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0; + it->size = data.size(); + it->padding = data.size() % 1; + + const int diff = it->size + it->padding - originalSize; // Now update the internal offsets - for(i++; i < d->chunks.size(); i++) - d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding; + for(++it; it != d->chunks.end(); ++it) + it->offset += diff; + + // Update the global size. + + updateGlobalSize(); } void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data) @@ -169,7 +198,7 @@ } if(!alwaysCreate) { - for(uint i = 0; i < d->chunks.size(); i++) { + for(unsigned int i = 0; i < d->chunks.size(); i++) { if(d->chunks[i].name == name) { setChunkData(i, data); return; @@ -179,48 +208,63 @@ // Couldn't find an existing chunk, so let's create a new one. - uint i = d->chunks.size() - 1; - ulong offset = d->chunks[i].offset + d->chunks[i].size; + // Adjust the padding of the last chunk to place the new chunk at even position. - // First we update the global size + Chunk &last = d->chunks.back(); - d->size += (offset & 1) + data.size() + 8; - insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4); + long offset = last.offset + last.size + last.padding; + if(offset & 1) { + if(last.padding == 1) { + last.padding = 0; // This should not happen unless the file is corrupted. + offset--; + removeBlock(offset, 1); + } + else { + insert(ByteVector("\0", 1), offset, 0); + last.padding = 1; + offset++; + } + } - // Now add the chunk to the file + // Now add the chunk to the file. - writeChunk(name, data, offset, std::max(0, length() - offset), (offset & 1) ? 1 : 0); + writeChunk(name, data, offset, 0); // And update our internal structure - if (offset & 1) { - d->chunks[i].padding = 1; - offset++; - } - Chunk chunk; - chunk.name = name; - chunk.size = data.size(); - chunk.offset = offset + 8; - chunk.padding = (data.size() & 0x01) ? 1 : 0; + chunk.name = name; + chunk.size = data.size(); + chunk.offset = offset + 8; + chunk.padding = data.size() % 2; d->chunks.push_back(chunk); + + // Update the global size. + + updateGlobalSize(); } -void RIFF::File::removeChunk(uint i) +void RIFF::File::removeChunk(unsigned int i) { - if(i >= d->chunks.size()) + if(i >= d->chunks.size()) { + debug("RIFF::File::removeChunk() - Index out of range."); return; + } std::vector::iterator it = d->chunks.begin(); std::advance(it, i); - const uint removeSize = it->size + it->padding + 8; + const unsigned int removeSize = it->size + it->padding + 8; removeBlock(it->offset - 8, removeSize); it = d->chunks.erase(it); for(; it != d->chunks.end(); ++it) it->offset -= removeSize; + + // Update the global size. + + updateGlobalSize(); } void RIFF::File::removeChunk(const ByteVector &name) @@ -235,81 +279,88 @@ // private members //////////////////////////////////////////////////////////////////////////////// -static bool isValidChunkID(const ByteVector &name) -{ - if(name.size() != 4) { - return false; - } - for(int i = 0; i < 4; i++) { - if(name[i] < 32 || name[i] > 127) { - return false; - } - } - return true; -} - void RIFF::File::read() { - bool bigEndian = (d->endianness == BigEndian); + const bool bigEndian = (d->endianness == BigEndian); + + long offset = tell(); - d->type = readBlock(4); + offset += 4; + d->sizeOffset = offset; + + seek(offset); d->size = readBlock(4).toUInt(bigEndian); - d->format = readBlock(4); + + offset += 8; + seek(offset); // + 8: chunk header at least, fix for additional junk bytes - while(tell() + 8 <= length()) { - ByteVector chunkName = readBlock(4); - uint chunkSize = readBlock(4).toUInt(bigEndian); + while(offset + 8 <= length()) { - if(!isValidChunkID(chunkName)) { + seek(offset); + const ByteVector chunkName = readBlock(4); + const unsigned int chunkSize = readBlock(4).toUInt(bigEndian); + + if(!isValidChunkName(chunkName)) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID"); setValid(false); break; } - if(static_cast(tell()) + chunkSize > static_cast(length())) { + if(static_cast(tell()) + chunkSize > length()) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)"); setValid(false); break; } + offset += 8; + Chunk chunk; - chunk.name = chunkName; - chunk.size = chunkSize; - chunk.offset = tell(); + chunk.name = chunkName; + chunk.size = chunkSize; + chunk.offset = offset; - seek(chunk.size, Current); + offset += chunk.size; + + seek(offset); + + // Check padding - // check padding chunk.padding = 0; - long uPosNotPadded = tell(); - if((uPosNotPadded & 0x01) != 0) { - ByteVector iByte = readBlock(1); - if((iByte.size() != 1) || (iByte[0] != 0)) { - // not well formed, re-seek - seek(uPosNotPadded, Beginning); - } - else { + + if(offset & 1) { + const ByteVector iByte = readBlock(1); + if(iByte.size() == 1 && iByte[0] == '\0') { chunk.padding = 1; + offset++; } } - d->chunks.push_back(chunk); + d->chunks.push_back(chunk); } } void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, - ulong offset, ulong replace, uint leadingPadding) + unsigned long offset, unsigned long replace) { ByteVector combined; - if(leadingPadding) { - combined.append(ByteVector(leadingPadding, '\x00')); - } + combined.append(name); combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian)); combined.append(data); - if((data.size() & 0x01) != 0) { - combined.append('\x00'); - } + + if(data.size() & 1) + combined.resize(combined.size() + 1, '\0'); + insert(combined, offset, replace); } + +void RIFF::File::updateGlobalSize() +{ + const Chunk first = d->chunks.front(); + const Chunk last = d->chunks.back(); + d->size = last.offset + last.size + last.padding - first.offset + 12; + + const ByteVector data = ByteVector::fromUInt(d->size, d->endianness == BigEndian); + insert(data, d->sizeOffset, 4); +} diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/rifffile.h clementine-1.3.1-218/3rdparty/taglib/riff/rifffile.h --- clementine-1.3.1-217/3rdparty/taglib/riff/rifffile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/rifffile.h 2016-07-19 15:25:23.000000000 +0000 @@ -61,46 +61,46 @@ /*! * \return The size of the main RIFF chunk. */ - uint riffSize() const; + unsigned int riffSize() const; /*! * \return The number of chunks in the file. */ - uint chunkCount() const; + unsigned int chunkCount() const; /*! * \return The offset within the file for the selected chunk number. */ - uint chunkOffset(uint i) const; + unsigned int chunkOffset(unsigned int i) const; /*! * \return The size of the chunk data. */ - uint chunkDataSize(uint i) const; + unsigned int chunkDataSize(unsigned int i) const; /*! * \return The size of the padding after the chunk (can be either 0 or 1). */ - uint chunkPadding(uint i) const; + unsigned int chunkPadding(unsigned int i) const; /*! * \return The name of the specified chunk, for instance, "COMM" or "ID3 " */ - ByteVector chunkName(uint i) const; + ByteVector chunkName(unsigned int i) const; /*! * Reads the chunk data from the file and returns it. * * \note This \e will move the read pointer for the file. */ - ByteVector chunkData(uint i); + ByteVector chunkData(unsigned int i); /*! * Sets the data for the specified chunk to \a data. * * \warning This will update the file immediately. */ - void setChunkData(uint i, const ByteVector &data); + void setChunkData(unsigned int i, const ByteVector &data); /*! * Sets the data for the chunk \a name to \a data. If a chunk with the @@ -129,7 +129,7 @@ * * \warning This will update the file immediately. */ - void removeChunk(uint i); + void removeChunk(unsigned int i); /*! * Removes the chunk \a name. @@ -145,8 +145,12 @@ void read(); void writeChunk(const ByteVector &name, const ByteVector &data, - ulong offset, ulong replace = 0, - uint leadingPadding = 0); + unsigned long offset, unsigned long replace = 0); + + /*! + * Update the global RIFF size based on the current internal structure. + */ + void updateGlobalSize(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/riffutils.h clementine-1.3.1-218/3rdparty/taglib/riff/riffutils.h --- clementine-1.3.1-217/3rdparty/taglib/riff/riffutils.h 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/riffutils.h 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,60 @@ +/*************************************************************************** + copyright : (C) 2015 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_RIFFUTILS_H +#define TAGLIB_RIFFUTILS_H + +// THIS FILE IS NOT A PART OF THE TAGLIB API + +#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header + +namespace TagLib +{ + namespace RIFF + { + namespace + { + + inline bool isValidChunkName(const ByteVector &name) + { + if(name.size() != 4) + return false; + + for(ByteVector::ConstIterator it = name.begin(); it != name.end(); ++it) { + const int c = static_cast(*it); + if(c < 32 || 127 < c) + return false; + } + + return true; + } + + } + } +} + +#endif + +#endif diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/wav/infotag.cpp clementine-1.3.1-218/3rdparty/taglib/riff/wav/infotag.cpp --- clementine-1.3.1-217/3rdparty/taglib/riff/wav/infotag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/wav/infotag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -27,34 +27,21 @@ #include #include "infotag.h" +#include "riffutils.h" using namespace TagLib; using namespace RIFF::Info; -namespace { - static bool isValidChunkID(const ByteVector &name) - { - if(name.size() != 4) - return false; - - for(int i = 0; i < 4; i++) { - if(name[i] < 32 || name[i] > 127) - return false; - } - - return true; - } +namespace +{ + const RIFF::Info::StringHandler defaultStringHandler; + const RIFF::Info::StringHandler *stringHandler = &defaultStringHandler; } class RIFF::Info::Tag::TagPrivate { public: - TagPrivate() - {} - FieldListMap fieldListMap; - - static const StringHandler *stringHandler; }; //////////////////////////////////////////////////////////////////////////////// @@ -83,19 +70,16 @@ // public members //////////////////////////////////////////////////////////////////////////////// -static const StringHandler defaultStringHandler; -const RIFF::Info::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler; - -RIFF::Info::Tag::Tag(const ByteVector &data) - : TagLib::Tag() - , d(new TagPrivate()) +RIFF::Info::Tag::Tag(const ByteVector &data) : + TagLib::Tag(), + d(new TagPrivate()) { parse(data); } -RIFF::Info::Tag::Tag() - : TagLib::Tag() - , d(new TagPrivate()) +RIFF::Info::Tag::Tag() : + TagLib::Tag(), + d(new TagPrivate()) { } @@ -129,12 +113,12 @@ return fieldText("IGNR"); } -TagLib::uint RIFF::Info::Tag::year() const +unsigned int RIFF::Info::Tag::year() const { return fieldText("ICRD").substr(0, 4).toInt(); } -TagLib::uint RIFF::Info::Tag::track() const +unsigned int RIFF::Info::Tag::track() const { return fieldText("IPRT").toInt(); } @@ -164,7 +148,7 @@ setFieldText("IGNR", s); } -void RIFF::Info::Tag::setYear(uint i) +void RIFF::Info::Tag::setYear(unsigned int i) { if(i != 0) setFieldText("ICRD", String::number(i)); @@ -172,7 +156,7 @@ d->fieldListMap.erase("ICRD"); } -void RIFF::Info::Tag::setTrack(uint i) +void RIFF::Info::Tag::setTrack(unsigned int i) { if(i != 0) setFieldText("IPRT", String::number(i)); @@ -201,7 +185,7 @@ void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s) { // id must be four-byte long pure ascii string. - if(!isValidChunkID(id)) + if(!isValidChunkName(id)) return; if(!s.isEmpty()) @@ -222,7 +206,7 @@ FieldListMap::ConstIterator it = d->fieldListMap.begin(); for(; it != d->fieldListMap.end(); ++it) { - ByteVector text = TagPrivate::stringHandler->render(it->second); + ByteVector text = stringHandler->render(it->second); if(text.isEmpty()) continue; @@ -244,9 +228,9 @@ void RIFF::Info::Tag::setStringHandler(const StringHandler *handler) { if(handler) - TagPrivate::stringHandler = handler; + stringHandler = handler; else - TagPrivate::stringHandler = &defaultStringHandler; + stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// @@ -255,15 +239,15 @@ void RIFF::Info::Tag::parse(const ByteVector &data) { - uint p = 4; + unsigned int p = 4; while(p < data.size()) { - const uint size = data.toUInt(p + 4, false); + const unsigned int size = data.toUInt(p + 4, false); if(size > data.size() - p - 8) break; const ByteVector id = data.mid(p, 4); - if(isValidChunkID(id)) { - const String text = TagPrivate::stringHandler->parse(data.mid(p + 8, size)); + if(isValidChunkName(id)) { + const String text = stringHandler->parse(data.mid(p + 8, size)); d->fieldListMap[id] = text; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/wav/infotag.h clementine-1.3.1-218/3rdparty/taglib/riff/wav/infotag.h --- clementine-1.3.1-217/3rdparty/taglib/riff/wav/infotag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/wav/infotag.h 2016-07-19 15:25:23.000000000 +0000 @@ -107,16 +107,16 @@ virtual String album() const; virtual String comment() const; virtual String genre() const; - virtual uint year() const; - virtual uint track() const; + virtual unsigned int year() const; + virtual unsigned int track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); - virtual void setYear(uint i); - virtual void setTrack(uint i); + virtual void setYear(unsigned int i); + virtual void setTrack(unsigned int i); virtual bool isEmpty() const; diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavfile.cpp clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -45,11 +45,8 @@ public: FilePrivate() : properties(0), - tagChunkID("ID3 "), hasID3v2(false), - hasInfo(false) - { - } + hasInfo(false) {} ~FilePrivate() { @@ -57,9 +54,6 @@ } Properties *properties; - - ByteVector tagChunkID; - TagUnion tag; bool hasID3v2; @@ -106,19 +100,31 @@ return d->tag.access(InfoIndex, false); } +void RIFF::WAV::File::strip(TagTypes tags) +{ + removeTagChunks(tags); + + if(tags & ID3v2) + d->tag.set(ID3v2Index, new ID3v2::Tag()); + + if(tags & Info) + d->tag.set(InfoIndex, new RIFF::Info::Tag()); +} + PropertyMap RIFF::WAV::File::properties() const { - return tag()->properties(); + return d->tag.properties(); } void RIFF::WAV::File::removeUnsupportedProperties(const StringList &unsupported) { - tag()->removeUnsupportedProperties(unsupported); + d->tag.removeUnsupportedProperties(unsupported); } PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) { - return tag()->setProperties(properties); + InfoTag()->setProperties(properties); + return ID3v2Tag()->setProperties(properties); } RIFF::WAV::Properties *RIFF::WAV::File::audioProperties() const @@ -146,28 +152,20 @@ if(stripOthers) strip(static_cast(AllTags & ~tags)); - const ID3v2::Tag *id3v2tag = d->tag.access(ID3v2Index, false); if(tags & ID3v2) { - if(d->hasID3v2) { - removeChunk(d->tagChunkID); - d->hasID3v2 = false; - } + removeTagChunks(ID3v2); - if(!id3v2tag->isEmpty()) { - setChunkData(d->tagChunkID, id3v2tag->render(id3v2Version)); + if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { + setChunkData("ID3 ", ID3v2Tag()->render(id3v2Version)); d->hasID3v2 = true; } } - const Info::Tag *infotag = d->tag.access(InfoIndex, false); if(tags & Info) { - if(d->hasInfo) { - removeChunk(findInfoTagChunk()); - d->hasInfo = false; - } + removeTagChunks(Info); - if(!infotag->isEmpty()) { - setChunkData("LIST", infotag->render(), true); + if(InfoTag() && !InfoTag()->isEmpty()) { + setChunkData("LIST", InfoTag()->render(), true); d->hasInfo = true; } } @@ -191,11 +189,10 @@ void RIFF::WAV::File::read(bool readProperties) { - for(uint i = 0; i < chunkCount(); ++i) { + for(unsigned int i = 0; i < chunkCount(); ++i) { const ByteVector name = chunkName(i); if(name == "ID3 " || name == "id3 ") { if(!d->tag[ID3v2Index]) { - d->tagChunkID = name; d->tag.set(ID3v2Index, new ID3v2::Tag(this, chunkOffset(i))); d->hasID3v2 = true; } @@ -227,29 +224,21 @@ d->properties = new Properties(this, Properties::Average); } -void RIFF::WAV::File::strip(TagTypes tags) +void RIFF::WAV::File::removeTagChunks(TagTypes tags) { - if(tags & ID3v2) { - removeChunk(d->tagChunkID); + if((tags & ID3v2) && d->hasID3v2) { + removeChunk("ID3 "); + removeChunk("id3 "); + d->hasID3v2 = false; } - if(tags & Info){ - TagLib::uint chunkId = findInfoTagChunk(); - if(chunkId != TagLib::uint(-1)) { - removeChunk(chunkId); - d->hasInfo = false; + if((tags & Info) && d->hasInfo) { + for(int i = static_cast(chunkCount()) - 1; i >= 0; --i) { + if(chunkName(i) == "LIST" && chunkData(i).startsWith("INFO")) + removeChunk(i); } - } -} -TagLib::uint RIFF::WAV::File::findInfoTagChunk() -{ - for(uint i = 0; i < chunkCount(); ++i) { - if(chunkName(i) == "LIST" && chunkData(i).startsWith("INFO")) { - return i; - } + d->hasInfo = false; } - - return TagLib::uint(-1); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavfile.h clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavfile.h --- clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -126,6 +126,15 @@ Info::Tag *InfoTag() const; /*! + * This will strip the tags that match the OR-ed together TagTypes from the + * file. By default it strips all tags. It returns true if the tags are + * successfully stripped. + * + * \note This will update the file immediately. + */ + void strip(TagTypes tags = AllTags); + + /*! * Implements the unified property interface -- export function. * This method forwards to ID3v2::Tag::properties(). */ @@ -171,13 +180,7 @@ File &operator=(const File &); void read(bool readProperties); - - void strip(TagTypes tags); - - /*! - * Returns the index of the chunk that its name is "LIST" and list type is "INFO". - */ - uint findInfoTagChunk(); + void removeTagChunks(TagTypes tags); friend class Properties; diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavproperties.cpp clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -57,21 +57,21 @@ int sampleRate; int channels; int bitsPerSample; - uint sampleFrames; + unsigned int sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -RIFF::WAV::Properties::Properties(const ByteVector & /*data*/, ReadStyle style) : +RIFF::WAV::Properties::Properties(const ByteVector &, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) { debug("RIFF::WAV::Properties::Properties() -- This constructor is no longer used."); } -RIFF::WAV::Properties::Properties(const ByteVector & /*data*/, uint /*streamLength*/, ReadStyle style) : +RIFF::WAV::Properties::Properties(const ByteVector &, unsigned int, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) { @@ -130,7 +130,7 @@ return bitsPerSample(); } -TagLib::uint RIFF::WAV::Properties::sampleFrames() const +unsigned int RIFF::WAV::Properties::sampleFrames() const { return d->sampleFrames; } @@ -147,10 +147,10 @@ void RIFF::WAV::Properties::read(File *file) { ByteVector data; - uint streamLength = 0; - uint totalSamples = 0; + unsigned int streamLength = 0; + unsigned int totalSamples = 0; - for(uint i = 0; i < file->chunkCount(); ++i) { + for(unsigned int i = 0; i < file->chunkCount(); ++i) { const ByteVector name = file->chunkName(i); if(name == "fmt ") { if(data.isEmpty()) @@ -192,7 +192,7 @@ d->sampleRate = data.toUInt(4, false); d->bitsPerSample = data.toShort(14, false); - if(totalSamples > 0) + if(d->format != FORMAT_PCM) d->sampleFrames = totalSamples; else if(d->channels > 0 && d->bitsPerSample > 0) d->sampleFrames = streamLength / (d->channels * ((d->bitsPerSample + 7) / 8)); @@ -203,7 +203,7 @@ d->bitrate = static_cast(streamLength * 8.0 / length + 0.5); } else { - const uint byteRate = data.toUInt(8, false); + const unsigned int byteRate = data.toUInt(8, false); if(byteRate > 0) { d->length = static_cast(streamLength * 1000.0 / byteRate + 0.5); d->bitrate = static_cast(byteRate * 8.0 / 1000.0 + 0.5); diff -Nru clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavproperties.h clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavproperties.h --- clementine-1.3.1-217/3rdparty/taglib/riff/wav/wavproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/riff/wav/wavproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -63,7 +63,7 @@ * * \deprecated */ - Properties(const ByteVector &data, uint streamLength, ReadStyle style); + Properties(const ByteVector &data, unsigned int streamLength, ReadStyle style); /*! * Create an instance of WAV::Properties with the data read from the @@ -135,7 +135,7 @@ /*! * Returns the number of sample frames. */ - uint sampleFrames() const; + unsigned int sampleFrames() const; /*! * Returns the format ID of the file. diff -Nru clementine-1.3.1-217/3rdparty/taglib/s3m/s3mfile.cpp clementine-1.3.1-218/3rdparty/taglib/s3m/s3mfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/s3m/s3mfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/s3m/s3mfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "s3mfile.h" #include "tstringlist.h" #include "tdebug.h" @@ -100,8 +105,8 @@ seek(32); - ushort length = 0; - ushort sampleCount = 0; + unsigned short length = 0; + unsigned short sampleCount = 0; if(!readU16L(length) || !readU16L(sampleCount)) return false; @@ -110,7 +115,7 @@ int channels = 0; for(int i = 0; i < 32; ++ i) { - uchar setting = 0; + unsigned char setting = 0; if(!readByte(setting)) return false; // or if(setting >= 128)? @@ -123,10 +128,10 @@ StringList lines = d->tag.comment().split("\n"); // write comment as sample names: - for(ushort i = 0; i < sampleCount; ++ i) { + for(unsigned short i = 0; i < sampleCount; ++ i) { seek(96L + length + ((long)i << 1)); - ushort instrumentOffset = 0; + unsigned short instrumentOffset = 0; if(!readU16L(instrumentOffset)) return false; seek(((long)instrumentOffset << 4) + 48); @@ -134,7 +139,7 @@ if(i < lines.size()) writeString(lines[i], 27); else - writeString(String::null, 27); + writeString(String(), 27); // string terminating NUL is not optional: writeByte(0); } @@ -193,8 +198,8 @@ d->properties.setChannels(channels); seek(96); - ushort realLength = 0; - for(ushort i = 0; i < length; ++ i) { + unsigned short realLength = 0; + for(unsigned short i = 0; i < length; ++ i) { READ_BYTE_AS(order); if(order == 255) break; if(order != 254) ++ realLength; @@ -208,7 +213,7 @@ // However, there I never found instruments (SCRI) but // instead samples (SCRS). StringList comment; - for(ushort i = 0; i < sampleCount; ++ i) { + for(unsigned short i = 0; i < sampleCount; ++ i) { seek(96L + length + ((long)i << 1)); READ_U16L_AS(sampleHeaderOffset); diff -Nru clementine-1.3.1-217/3rdparty/taglib/s3m/s3mfile.h clementine-1.3.1-218/3rdparty/taglib/s3m/s3mfile.h --- clementine-1.3.1-217/3rdparty/taglib/s3m/s3mfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/s3m/s3mfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_S3MFILE_H diff -Nru clementine-1.3.1-217/3rdparty/taglib/s3m/s3mproperties.cpp clementine-1.3.1-218/3rdparty/taglib/s3m/s3mproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/s3m/s3mproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/s3m/s3mproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "s3mproperties.h" using namespace TagLib; @@ -43,18 +48,18 @@ { } - ushort lengthInPatterns; - int channels; - bool stereo; - ushort sampleCount; - ushort patternCount; - ushort flags; - ushort trackerVersion; - ushort fileFormatVersion; - uchar globalVolume; - uchar masterVolume; - uchar tempo; - uchar bpmSpeed; + unsigned short lengthInPatterns; + int channels; + bool stereo; + unsigned short sampleCount; + unsigned short patternCount; + unsigned short flags; + unsigned short trackerVersion; + unsigned short fileFormatVersion; + unsigned char globalVolume; + unsigned char masterVolume; + unsigned char tempo; + unsigned char bpmSpeed; }; S3M::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : @@ -98,7 +103,7 @@ return d->channels; } -TagLib::ushort S3M::Properties::lengthInPatterns() const +unsigned short S3M::Properties::lengthInPatterns() const { return d->lengthInPatterns; } @@ -108,52 +113,52 @@ return d->stereo; } -TagLib::ushort S3M::Properties::sampleCount() const +unsigned short S3M::Properties::sampleCount() const { return d->sampleCount; } -TagLib::ushort S3M::Properties::patternCount() const +unsigned short S3M::Properties::patternCount() const { return d->patternCount; } -TagLib::ushort S3M::Properties::flags() const +unsigned short S3M::Properties::flags() const { return d->flags; } -TagLib::ushort S3M::Properties::trackerVersion() const +unsigned short S3M::Properties::trackerVersion() const { return d->trackerVersion; } -TagLib::ushort S3M::Properties::fileFormatVersion() const +unsigned short S3M::Properties::fileFormatVersion() const { return d->fileFormatVersion; } -uchar S3M::Properties::globalVolume() const +unsigned char S3M::Properties::globalVolume() const { return d->globalVolume; } -uchar S3M::Properties::masterVolume() const +unsigned char S3M::Properties::masterVolume() const { return d->masterVolume; } -uchar S3M::Properties::tempo() const +unsigned char S3M::Properties::tempo() const { return d->tempo; } -uchar S3M::Properties::bpmSpeed() const +unsigned char S3M::Properties::bpmSpeed() const { return d->bpmSpeed; } -void S3M::Properties::setLengthInPatterns(ushort lengthInPatterns) +void S3M::Properties::setLengthInPatterns(unsigned short lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } @@ -168,47 +173,47 @@ d->stereo = stereo; } -void S3M::Properties::setSampleCount(ushort sampleCount) +void S3M::Properties::setSampleCount(unsigned short sampleCount) { d->sampleCount = sampleCount; } -void S3M::Properties::setPatternCount(ushort patternCount) +void S3M::Properties::setPatternCount(unsigned short patternCount) { d->patternCount = patternCount; } -void S3M::Properties::setFlags(ushort flags) +void S3M::Properties::setFlags(unsigned short flags) { d->flags = flags; } -void S3M::Properties::setTrackerVersion(ushort trackerVersion) +void S3M::Properties::setTrackerVersion(unsigned short trackerVersion) { d->trackerVersion = trackerVersion; } -void S3M::Properties::setFileFormatVersion(ushort fileFormatVersion) +void S3M::Properties::setFileFormatVersion(unsigned short fileFormatVersion) { d->fileFormatVersion = fileFormatVersion; } -void S3M::Properties::setGlobalVolume(uchar globalVolume) +void S3M::Properties::setGlobalVolume(unsigned char globalVolume) { d->globalVolume = globalVolume; } -void S3M::Properties::setMasterVolume(uchar masterVolume) +void S3M::Properties::setMasterVolume(unsigned char masterVolume) { d->masterVolume = masterVolume; } -void S3M::Properties::setTempo(uchar tempo) +void S3M::Properties::setTempo(unsigned char tempo) { d->tempo = tempo; } -void S3M::Properties::setBpmSpeed(uchar bpmSpeed) +void S3M::Properties::setBpmSpeed(unsigned char bpmSpeed) { d->bpmSpeed = bpmSpeed; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/s3m/s3mproperties.h clementine-1.3.1-218/3rdparty/taglib/s3m/s3mproperties.h --- clementine-1.3.1-217/3rdparty/taglib/s3m/s3mproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/s3m/s3mproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_S3MPROPERTIES_H @@ -51,31 +55,31 @@ int sampleRate() const; int channels() const; - ushort lengthInPatterns() const; - bool stereo() const; - ushort sampleCount() const; - ushort patternCount() const; - ushort flags() const; - ushort trackerVersion() const; - ushort fileFormatVersion() const; - uchar globalVolume() const; - uchar masterVolume() const; - uchar tempo() const; - uchar bpmSpeed() const; + unsigned short lengthInPatterns() const; + bool stereo() const; + unsigned short sampleCount() const; + unsigned short patternCount() const; + unsigned short flags() const; + unsigned short trackerVersion() const; + unsigned short fileFormatVersion() const; + unsigned char globalVolume() const; + unsigned char masterVolume() const; + unsigned char tempo() const; + unsigned char bpmSpeed() const; void setChannels(int channels); - void setLengthInPatterns (ushort lengthInPatterns); + void setLengthInPatterns (unsigned short lengthInPatterns); void setStereo (bool stereo); - void setSampleCount (ushort sampleCount); - void setPatternCount (ushort patternCount); - void setFlags (ushort flags); - void setTrackerVersion (ushort trackerVersion); - void setFileFormatVersion(ushort fileFormatVersion); - void setGlobalVolume (uchar globalVolume); - void setMasterVolume (uchar masterVolume); - void setTempo (uchar tempo); - void setBpmSpeed (uchar bpmSpeed); + void setSampleCount (unsigned short sampleCount); + void setPatternCount (unsigned short patternCount); + void setFlags (unsigned short flags); + void setTrackerVersion (unsigned short trackerVersion); + void setFileFormatVersion(unsigned short fileFormatVersion); + void setGlobalVolume (unsigned char globalVolume); + void setMasterVolume (unsigned char masterVolume); + void setTempo (unsigned char tempo); + void setBpmSpeed (unsigned char bpmSpeed); private: Properties(const Properties&); diff -Nru clementine-1.3.1-217/3rdparty/taglib/tag.cpp clementine-1.3.1-218/3rdparty/taglib/tag.cpp --- clementine-1.3.1-217/3rdparty/taglib/tag.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/tag.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -58,15 +58,15 @@ PropertyMap Tag::properties() const { PropertyMap map; - if(!(title().isNull())) + if(!(title().isEmpty())) map["TITLE"].append(title()); - if(!(artist().isNull())) + if(!(artist().isEmpty())) map["ARTIST"].append(artist()); - if(!(album().isNull())) + if(!(album().isEmpty())) map["ALBUM"].append(album()); - if(!(comment().isNull())) + if(!(comment().isEmpty())) map["COMMENT"].append(comment()); - if(!(genre().isNull())) + if(!(genre().isEmpty())) map["GENRE"].append(genre()); if(!(year() == 0)) map["DATE"].append(String::number(year())); @@ -89,31 +89,31 @@ setTitle(properties["TITLE"].front()); oneValueSet.append("TITLE"); } else - setTitle(String::null); + setTitle(String()); if(properties.contains("ARTIST")) { setArtist(properties["ARTIST"].front()); oneValueSet.append("ARTIST"); } else - setArtist(String::null); + setArtist(String()); if(properties.contains("ALBUM")) { setAlbum(properties["ALBUM"].front()); oneValueSet.append("ALBUM"); } else - setAlbum(String::null); + setAlbum(String()); if(properties.contains("COMMENT")) { setComment(properties["COMMENT"].front()); oneValueSet.append("COMMENT"); } else - setComment(String::null); + setComment(String()); if(properties.contains("GENRE")) { setGenre(properties["GENRE"].front()); oneValueSet.append("GENRE"); } else - setGenre(String::null); + setGenre(String()); if(properties.contains("DATE")) { bool ok; diff -Nru clementine-1.3.1-217/3rdparty/taglib/tag.h clementine-1.3.1-218/3rdparty/taglib/tag.h --- clementine-1.3.1-217/3rdparty/taglib/tag.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/tag.h 2016-07-19 15:25:23.000000000 +0000 @@ -111,13 +111,13 @@ /*! * Returns the year; if there is no year set, this will return 0. */ - virtual uint year() const = 0; + virtual unsigned int year() const = 0; /*! * Returns the track number; if there is no track number set, this will * return 0. */ - virtual uint track() const = 0; + virtual unsigned int track() const = 0; /*! * Sets the title to \a s. If \a s is String::null then this value will be @@ -155,12 +155,12 @@ /*! * Sets the year to \a i. If \a s is 0 then this value will be cleared. */ - virtual void setYear(uint i) = 0; + virtual void setYear(unsigned int i) = 0; /*! * Sets the track to \a i. If \a s is 0 then this value will be cleared. */ - virtual void setTrack(uint i) = 0; + virtual void setTrack(unsigned int i) = 0; /*! * Returns true if the tag does not contain any data. This should be diff -Nru clementine-1.3.1-217/3rdparty/taglib/tagunion.cpp clementine-1.3.1-218/3rdparty/taglib/tagunion.cpp --- clementine-1.3.1-217/3rdparty/taglib/tagunion.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/tagunion.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,8 +23,15 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include "tagunion.h" -#include "tstringlist.h" +#include +#include +#include + +#include "id3v1tag.h" +#include "id3v2tag.h" +#include "apetag.h" +#include "xiphcomment.h" +#include "infotag.h" using namespace TagLib; @@ -35,7 +42,7 @@ return tag(1)->method(); \ if(tag(2) && !tag(2)->method().isEmpty()) \ return tag(2)->method(); \ - return String::null \ + return String(); \ #define numberUnion(method) \ if(tag(0) && tag(0)->method() > 0) \ @@ -102,6 +109,62 @@ d->tags[index] = tag; } +PropertyMap TagUnion::properties() const +{ + // This is an ugly workaround but we can't add a virtual function. + // Should be virtual in taglib2. + + for(size_t i = 0; i < 3; ++i) { + + if(d->tags[i] && !d->tags[i]->isEmpty()) { + + if(dynamic_cast(d->tags[i])) + return dynamic_cast(d->tags[i])->properties(); + + else if(dynamic_cast(d->tags[i])) + return dynamic_cast(d->tags[i])->properties(); + + else if(dynamic_cast(d->tags[i])) + return dynamic_cast(d->tags[i])->properties(); + + else if(dynamic_cast(d->tags[i])) + return dynamic_cast(d->tags[i])->properties(); + + else if(dynamic_cast(d->tags[i])) + return dynamic_cast(d->tags[i])->properties(); + } + } + + return PropertyMap(); +} + +void TagUnion::removeUnsupportedProperties(const StringList &unsupported) +{ + // This is an ugly workaround but we can't add a virtual function. + // Should be virtual in taglib2. + + for(size_t i = 0; i < 3; ++i) { + + if(d->tags[i]) { + + if(dynamic_cast(d->tags[i])) + dynamic_cast(d->tags[i])->removeUnsupportedProperties(unsupported); + + else if(dynamic_cast(d->tags[i])) + dynamic_cast(d->tags[i])->removeUnsupportedProperties(unsupported); + + else if(dynamic_cast(d->tags[i])) + dynamic_cast(d->tags[i])->removeUnsupportedProperties(unsupported); + + else if(dynamic_cast(d->tags[i])) + dynamic_cast(d->tags[i])->removeUnsupportedProperties(unsupported); + + else if(dynamic_cast(d->tags[i])) + dynamic_cast(d->tags[i])->removeUnsupportedProperties(unsupported); + } + } +} + String TagUnion::title() const { stringUnion(title); @@ -127,12 +190,12 @@ stringUnion(genre); } -TagLib::uint TagUnion::year() const +unsigned int TagUnion::year() const { numberUnion(year); } -TagLib::uint TagUnion::track() const +unsigned int TagUnion::track() const { numberUnion(track); } @@ -162,12 +225,12 @@ setUnion(Genre, s); } -void TagUnion::setYear(uint i) +void TagUnion::setYear(unsigned int i) { setUnion(Year, i); } -void TagUnion::setTrack(uint i) +void TagUnion::setTrack(unsigned int i) { setUnion(Track, i); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/tagunion.h clementine-1.3.1-218/3rdparty/taglib/tagunion.h --- clementine-1.3.1-217/3rdparty/taglib/tagunion.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/tagunion.h 2016-07-19 15:25:23.000000000 +0000 @@ -56,21 +56,24 @@ void set(int index, Tag *tag); + PropertyMap properties() const; + void removeUnsupportedProperties(const StringList &unsupported); + virtual String title() const; virtual String artist() const; virtual String album() const; virtual String comment() const; virtual String genre() const; - virtual uint year() const; - virtual uint track() const; + virtual unsigned int year() const; + virtual unsigned int track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); - virtual void setYear(uint i); - virtual void setTrack(uint i); + virtual void setYear(unsigned int i); + virtual void setTrack(unsigned int i); virtual bool isEmpty() const; template T *access(int index, bool create) diff -Nru clementine-1.3.1-217/3rdparty/taglib/tagutils.cpp clementine-1.3.1-218/3rdparty/taglib/tagutils.cpp --- clementine-1.3.1-217/3rdparty/taglib/tagutils.cpp 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/tagutils.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,79 @@ +/*************************************************************************** + copyright : (C) 2015 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#include + +#include "id3v1tag.h" +#include "id3v2header.h" +#include "apetag.h" + +#include "tagutils.h" + +using namespace TagLib; + +long Utils::findID3v1(File *file) +{ + if(!file->isValid()) + return -1; + + file->seek(-128, File::End); + const long p = file->tell(); + + if(file->readBlock(3) == ID3v1::Tag::fileIdentifier()) + return p; + + return -1; +} + +long Utils::findID3v2(File *file) +{ + if(!file->isValid()) + return -1; + + file->seek(0); + + if(file->readBlock(3) == ID3v2::Header::fileIdentifier()) + return 0; + + return -1; +} + +long Utils::findAPE(File *file, long id3v1Location) +{ + if(!file->isValid()) + return -1; + + if(id3v1Location >= 0) + file->seek(id3v1Location - 32, File::Beginning); + else + file->seek(-32, File::End); + + const long p = file->tell(); + + if(file->readBlock(8) == APE::Tag::fileIdentifier()) + return p; + + return -1; +} diff -Nru clementine-1.3.1-217/3rdparty/taglib/tagutils.h clementine-1.3.1-218/3rdparty/taglib/tagutils.h --- clementine-1.3.1-217/3rdparty/taglib/tagutils.h 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/tagutils.h 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,49 @@ +/*************************************************************************** + copyright : (C) 2015 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_TAGUTILS_H +#define TAGLIB_TAGUTILS_H + +// THIS FILE IS NOT A PART OF THE TAGLIB API + +#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header + +namespace TagLib { + + class File; + + namespace Utils { + + long findID3v1(File *file); + + long findID3v2(File *file); + + long findAPE(File *file, long id3v1Location); + } +} + +#endif + +#endif diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/taglib.h clementine-1.3.1-218/3rdparty/taglib/toolkit/taglib.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/taglib.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/taglib.h 2016-07-19 15:25:23.000000000 +0000 @@ -29,10 +29,10 @@ #include "taglib_config.h" #define TAGLIB_MAJOR_VERSION 1 -#define TAGLIB_MINOR_VERSION 10 +#define TAGLIB_MINOR_VERSION 11 #define TAGLIB_PATCH_VERSION 0 -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) || defined(__clang__) #define TAGLIB_IGNORE_MISSING_DESTRUCTOR _Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") #else #define TAGLIB_IGNORE_MISSING_DESTRUCTOR @@ -60,20 +60,20 @@ class String; + // These integer types are deprecated. Do not use them. + typedef wchar_t wchar; // Assumed to be sufficient to store a UTF-16 char. typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; + typedef unsigned long ulong; typedef unsigned long long ulonglong; - // long/ulong can be either 32-bit or 64-bit wide. - typedef unsigned long ulong; - /*! * Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3) * so I'm providing something here that should be constant. */ - typedef std::basic_string wstring; + typedef std::basic_string wstring; } /*! diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevector.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevector.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevector.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevector.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include @@ -37,8 +33,8 @@ #include #include -#include "trefcounter.h" -#include "tutils.h" +#include +#include #include "tbytevector.h" @@ -49,66 +45,12 @@ // // http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp -#define DATA(x) (&(x->data->data[0])) - namespace TagLib { -static const char hexTable[17] = "0123456789abcdef"; - -static const uint crcTable[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, - 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, - 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, - 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, - 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, - 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, - 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, - 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, - 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, - 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, - 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, - 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, - 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, - 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, - 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, - 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, - 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, - 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, - 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, - 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, - 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, - 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 -}; - -/*! - * A templatized straightforward find that works with the types - * std::vector::iterator and std::vector::reverse_iterator. - */ template int findChar( const TIterator dataBegin, const TIterator dataEnd, - char c, uint offset, int byteAlign) + char c, unsigned int offset, int byteAlign) { const size_t dataSize = dataEnd - dataBegin; if(offset + 1 > dataSize) @@ -127,61 +69,44 @@ return -1; } -/*! - * A templatized KMP find that works with the types - * std::vector::iterator and std::vector::reverse_iterator. - */ template int findVector( const TIterator dataBegin, const TIterator dataEnd, const TIterator patternBegin, const TIterator patternEnd, - uint offset, int byteAlign) + unsigned int offset, int byteAlign) { const size_t dataSize = dataEnd - dataBegin; const size_t patternSize = patternEnd - patternBegin; if(patternSize == 0 || offset + patternSize > dataSize) return -1; - // n % 0 is invalid - - if(byteAlign == 0) - return -1; - // Special case that pattern contains just single char. if(patternSize == 1) return findChar(dataBegin, dataEnd, *patternBegin, offset, byteAlign); - size_t lastOccurrence[256]; + // n % 0 is invalid - for(size_t i = 0; i < 256; ++i) - lastOccurrence[i] = patternSize; + if(byteAlign == 0) + return -1; - for(size_t i = 0; i < patternSize - 1; ++i) - lastOccurrence[static_cast(*(patternBegin + i))] = patternSize - i - 1; + // We don't use sophisticated algorithms like Knuth-Morris-Pratt here. - TIterator it = dataBegin + patternSize - 1 + offset; - while(true) { - TIterator itBuffer = it; - TIterator itPattern = patternBegin + patternSize - 1; - - while(*itBuffer == *itPattern) { - if(itPattern == patternBegin) { - if((itBuffer - dataBegin - offset) % byteAlign == 0) - return (itBuffer - dataBegin); - else - break; - } + // In the current implementation of TagLib, data and patterns are too small + // for such algorithms to work effectively. - --itBuffer; - --itPattern; - } + for(TIterator it = dataBegin + offset; it < dataEnd - patternSize + 1; it += byteAlign) { - const size_t step = lastOccurrence[static_cast(*it)]; - if(dataEnd - step <= it) - break; + TIterator itData = it; + TIterator itPattern = patternBegin; + + while(*itData == *itPattern) { + ++itData; + ++itPattern; - it += step; + if(itPattern == patternEnd) + return (it - dataBegin); + } } return -1; @@ -200,7 +125,7 @@ T sum = 0; for(size_t i = 0; i < length; i++) { const size_t shift = (mostSignificantByteFirst ? length - 1 - i : i) * 8; - sum |= static_cast(static_cast(v[offset + i])) << shift; + sum |= static_cast(static_cast(v[offset + i])) << shift; } return sum; @@ -275,20 +200,22 @@ template long double toFloat80(const ByteVector &v, size_t offset) { + using std::swap; + if(offset > v.size() - 10) { debug("toFloat80() - offset is out of range. Returning 0."); return 0.0; } - uchar bytes[10]; + unsigned char bytes[10]; ::memcpy(bytes, v.data() + offset, 10); if(ENDIAN == Utils::LittleEndian) { - std::swap(bytes[0], bytes[9]); - std::swap(bytes[1], bytes[8]); - std::swap(bytes[2], bytes[7]); - std::swap(bytes[3], bytes[6]); - std::swap(bytes[4], bytes[5]); + swap(bytes[0], bytes[9]); + swap(bytes[1], bytes[8]); + swap(bytes[2], bytes[7]); + swap(bytes[3], bytes[6]); + swap(bytes[4], bytes[5]); } // 1-bit sign @@ -298,15 +225,15 @@ const int exponent = ((bytes[0] & 0x7F) << 8) | bytes[1]; // 64-bit fraction. Leading 1 is explicit. - const ulonglong fraction - = (static_cast(bytes[2]) << 56) - | (static_cast(bytes[3]) << 48) - | (static_cast(bytes[4]) << 40) - | (static_cast(bytes[5]) << 32) - | (static_cast(bytes[6]) << 24) - | (static_cast(bytes[7]) << 16) - | (static_cast(bytes[8]) << 8) - | (static_cast(bytes[9])); + const unsigned long long fraction + = (static_cast(bytes[2]) << 56) + | (static_cast(bytes[3]) << 48) + | (static_cast(bytes[4]) << 40) + | (static_cast(bytes[5]) << 32) + | (static_cast(bytes[6]) << 24) + | (static_cast(bytes[7]) << 16) + | (static_cast(bytes[8]) << 8) + | (static_cast(bytes[9])); long double val; if(exponent == 0 && fraction == 0) @@ -326,108 +253,42 @@ return val; } -class DataPrivate : public RefCounter -{ -public: - DataPrivate() - { - } - - DataPrivate(const std::vector &v, uint offset, uint length) - : data(v.begin() + offset, v.begin() + offset + length) - { - } - - // A char* can be an iterator. - DataPrivate(const char *begin, const char *end) - : data(begin, end) - { - } - - DataPrivate(uint len, char c) - : data(len, c) - { - } - - std::vector data; -}; - -class ByteVector::ByteVectorPrivate : public RefCounter +class ByteVector::ByteVectorPrivate { public: - ByteVectorPrivate() - : RefCounter() - , data(new DataPrivate()) - , offset(0) - , length(0) - { - } - - ByteVectorPrivate(ByteVectorPrivate *d, uint o, uint l) - : RefCounter() - , data(d->data) - , offset(d->offset + o) - , length(l) + ByteVectorPrivate(unsigned int l, char c) : + counter(new RefCounter()), + data(new std::vector(l, c)), + offset(0), + length(l) {} + + ByteVectorPrivate(const char *s, unsigned int l) : + counter(new RefCounter()), + data(new std::vector(s, s + l)), + offset(0), + length(l) {} + + ByteVectorPrivate(const ByteVectorPrivate &d, unsigned int o, unsigned int l) : + counter(d.counter), + data(d.data), + offset(d.offset + o), + length(l) { - data->ref(); - } - - ByteVectorPrivate(const std::vector &v, uint o, uint l) - : RefCounter() - , data(new DataPrivate(v, o, l)) - , offset(0) - , length(l) - { - } - - ByteVectorPrivate(uint l, char c) - : RefCounter() - , data(new DataPrivate(l, c)) - , offset(0) - , length(l) - { - } - - ByteVectorPrivate(const char *s, uint l) - : RefCounter() - , data(new DataPrivate(s, s + l)) - , offset(0) - , length(l) - { - } - - void detach() - { - if(data->count() > 1) { - data->deref(); - data = new DataPrivate(data->data, offset, length); - offset = 0; - } + counter->ref(); } ~ByteVectorPrivate() { - if(data->deref()) + if(counter->deref()) { + delete counter; delete data; - } - - ByteVectorPrivate &operator=(const ByteVectorPrivate &x) - { - if(&x != this) - { - if(data->deref()) - delete data; - - data = x.data; - data->ref(); } - - return *this; } - DataPrivate *data; - uint offset; - uint length; + RefCounter *counter; + std::vector *data; + unsigned int offset; + unsigned int length; }; //////////////////////////////////////////////////////////////////////////////// @@ -436,7 +297,7 @@ ByteVector ByteVector::null; -ByteVector ByteVector::fromCString(const char *s, uint length) +ByteVector ByteVector::fromCString(const char *s, unsigned int length) { if(length == 0xffffffff) return ByteVector(s, ::strlen(s)); @@ -444,14 +305,14 @@ return ByteVector(s, length); } -ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) +ByteVector ByteVector::fromUInt(unsigned int value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, mostSignificantByteFirst); } ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, mostSignificantByteFirst); } ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) @@ -461,94 +322,92 @@ ByteVector ByteVector::fromFloat32LE(float value) { - return fromFloat(value); + return fromFloat(value); } ByteVector ByteVector::fromFloat32BE(float value) { - return fromFloat(value); + return fromFloat(value); } ByteVector ByteVector::fromFloat64LE(double value) { - return fromFloat(value); + return fromFloat(value); } ByteVector ByteVector::fromFloat64BE(double value) { - return fromFloat(value); + return fromFloat(value); } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -ByteVector::ByteVector() - : d(new ByteVectorPrivate()) +ByteVector::ByteVector() : + d(new ByteVectorPrivate(0, '\0')) { } -ByteVector::ByteVector(uint size, char value) - : d(new ByteVectorPrivate(size, value)) +ByteVector::ByteVector(unsigned int size, char value) : + d(new ByteVectorPrivate(size, value)) { } -ByteVector::ByteVector(const ByteVector &v) - : d(v.d) +ByteVector::ByteVector(const ByteVector &v) : + d(new ByteVectorPrivate(*v.d, 0, v.d->length)) { - d->ref(); } -ByteVector::ByteVector(const ByteVector &v, uint offset, uint length) - : d(new ByteVectorPrivate(v.d, offset, length)) +ByteVector::ByteVector(const ByteVector &v, unsigned int offset, unsigned int length) : + d(new ByteVectorPrivate(*v.d, offset, length)) { } -ByteVector::ByteVector(char c) - : d(new ByteVectorPrivate(1, c)) +ByteVector::ByteVector(char c) : + d(new ByteVectorPrivate(1, c)) { } -ByteVector::ByteVector(const char *data, uint length) - : d(new ByteVectorPrivate(data, length)) +ByteVector::ByteVector(const char *data, unsigned int length) : + d(new ByteVectorPrivate(data, length)) { } -ByteVector::ByteVector(const char *data) - : d(new ByteVectorPrivate(data, ::strlen(data))) +ByteVector::ByteVector(const char *data) : + d(new ByteVectorPrivate(data, ::strlen(data))) { } ByteVector::~ByteVector() { - if(d->deref()) - delete d; + delete d; } -ByteVector &ByteVector::setData(const char *s, uint length) +ByteVector &ByteVector::setData(const char *s, unsigned int length) { - *this = ByteVector(s, length); + ByteVector(s, length).swap(*this); return *this; } ByteVector &ByteVector::setData(const char *data) { - *this = ByteVector(data); + ByteVector(data).swap(*this); return *this; } char *ByteVector::data() { detach(); - return size() > 0 ? (DATA(d) + d->offset) : 0; + return (size() > 0) ? (&(*d->data)[d->offset]) : 0; } const char *ByteVector::data() const { - return size() > 0 ? (DATA(d) + d->offset) : 0; + return (size() > 0) ? (&(*d->data)[d->offset]) : 0; } -ByteVector ByteVector::mid(uint index, uint length) const +ByteVector ByteVector::mid(unsigned int index, unsigned int length) const { index = std::min(index, size()); length = std::min(length, size() - index); @@ -556,23 +415,23 @@ return ByteVector(*this, index, length); } -char ByteVector::at(uint index) const +char ByteVector::at(unsigned int index) const { - return index < size() ? DATA(d)[d->offset + index] : 0; + return (index < size()) ? (*d->data)[d->offset + index] : 0; } -int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const +int ByteVector::find(const ByteVector &pattern, unsigned int offset, int byteAlign) const { return findVector( begin(), end(), pattern.begin(), pattern.end(), offset, byteAlign); } -int ByteVector::find(char c, uint offset, int byteAlign) const +int ByteVector::find(char c, unsigned int offset, int byteAlign) const { return findChar(begin(), end(), c, offset, byteAlign); } -int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const +int ByteVector::rfind(const ByteVector &pattern, unsigned int offset, int byteAlign) const { if(offset > 0) { offset = size() - offset - pattern.size(); @@ -589,13 +448,13 @@ return size() - pos - pattern.size(); } -bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint patternOffset, uint patternLength) const +bool ByteVector::containsAt(const ByteVector &pattern, unsigned int offset, unsigned int patternOffset, unsigned int patternLength) const { if(pattern.size() < patternLength) patternLength = pattern.size(); // do some sanity checking -- all of these things are needed for the search to be valid - const uint compareLength = patternLength - patternOffset; + const unsigned int compareLength = patternLength - patternOffset; if(offset + compareLength > size() || patternOffset >= pattern.size() || patternLength == 0) return false; @@ -612,18 +471,34 @@ return containsAt(pattern, size() - pattern.size()); } +ByteVector &ByteVector::replace(char oldByte, char newByte) +{ + detach(); + + for(ByteVector::Iterator it = begin(); it != end(); ++it) { + if(*it == oldByte) + *it = newByte; + } + + return *this; +} + ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &with) { + // TODO: This takes O(n!) time in the worst case. Rewrite it to run in O(n) time. + if(pattern.size() == 0 || pattern.size() > size()) return *this; + if(pattern.size() == 1 && with.size() == 1) + return replace(pattern[0], with[0]); + const size_t withSize = with.size(); const size_t patternSize = pattern.size(); const ptrdiff_t diff = withSize - patternSize; size_t offset = 0; - while (true) - { + while (true) { offset = find(pattern, offset); if(offset == static_cast(-1)) // Use npos in taglib2. break; @@ -665,7 +540,7 @@ // try to match the last n-1 bytes from the vector (where n is the pattern // size) -- continue trying to match n-2, n-3...1 bytes - for(uint i = 1; i < pattern.size(); i++) { + for(unsigned int i = 1; i < pattern.size(); i++) { if(containsAt(pattern, startIndex + i, 0, pattern.size() - i)) return startIndex + i; } @@ -675,30 +550,38 @@ ByteVector &ByteVector::append(const ByteVector &v) { - if(v.d->length != 0) - { - detach(); + if(v.isEmpty()) + return *this; - uint originalSize = size(); - resize(originalSize + v.size()); - ::memcpy(data() + originalSize, v.data(), v.size()); - } + detach(); + + const unsigned int originalSize = size(); + const unsigned int appendSize = v.size(); + + resize(originalSize + appendSize); + ::memcpy(data() + originalSize, v.data(), appendSize); return *this; } +ByteVector &ByteVector::append(char c) +{ + resize(size() + 1, c); + return *this; +} + ByteVector &ByteVector::clear() { - *this = ByteVector(); + ByteVector().swap(*this); return *this; } -TagLib::uint ByteVector::size() const +unsigned int ByteVector::size() const { return d->length; } -ByteVector &ByteVector::resize(uint size, char padding) +ByteVector &ByteVector::resize(unsigned int size, char padding) { if(size != d->length) { detach(); @@ -707,8 +590,8 @@ // This doesn't reallocate the buffer, since std::vector::resize() doesn't // reallocate the buffer when shrinking. - d->data->data.resize(d->offset + d->length); - d->data->data.resize(d->offset + size, padding); + d->data->resize(d->offset + d->length); + d->data->resize(d->offset + size, padding); d->length = size; } @@ -719,45 +602,51 @@ ByteVector::Iterator ByteVector::begin() { detach(); - return d->data->data.begin() + d->offset; + return d->data->begin() + d->offset; } ByteVector::ConstIterator ByteVector::begin() const { - return d->data->data.begin() + d->offset; + return d->data->begin() + d->offset; } ByteVector::Iterator ByteVector::end() { detach(); - return d->data->data.begin() + d->offset + d->length; + return d->data->begin() + d->offset + d->length; } ByteVector::ConstIterator ByteVector::end() const { - return d->data->data.begin() + d->offset + d->length; + return d->data->begin() + d->offset + d->length; } ByteVector::ReverseIterator ByteVector::rbegin() { detach(); - return d->data->data.rbegin() + (d->data->data.size() - (d->offset + d->length)); + return d->data->rbegin() + (d->data->size() - (d->offset + d->length)); } ByteVector::ConstReverseIterator ByteVector::rbegin() const { - return d->data->data.rbegin() + (d->data->data.size() - (d->offset + d->length)); + // Workaround for the Solaris Studio 12.4 compiler. + // We need a const reference to the data vector so we can ensure the const version of rbegin() is called. + const std::vector &v = *d->data; + return v.rbegin() + (v.size() - (d->offset + d->length)); } ByteVector::ReverseIterator ByteVector::rend() { detach(); - return d->data->data.rbegin() + (d->data->data.size() - d->offset); + return d->data->rbegin() + (d->data->size() - d->offset); } ByteVector::ConstReverseIterator ByteVector::rend() const { - return d->data->data.rbegin() + (d->data->data.size() - d->offset); + // Workaround for the Solaris Studio 12.4 compiler. + // We need a const reference to the data vector so we can ensure the const version of rbegin() is called. + const std::vector &v = *d->data; + return v.rbegin() + (v.size() - d->offset); } bool ByteVector::isNull() const @@ -770,27 +659,73 @@ return (d->length == 0); } -TagLib::uint ByteVector::checksum() const +unsigned int ByteVector::checksum() const { - uint sum = 0; + static const unsigned int crcTable[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 + }; + + unsigned int sum = 0; for(ByteVector::ConstIterator it = begin(); it != end(); ++it) - sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ uchar(*it)]; + sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ static_cast(*it)]; return sum; } -TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const +unsigned int ByteVector::toUInt(bool mostSignificantByteFirst) const { - return toNumber(*this, 0, mostSignificantByteFirst); + return toNumber(*this, 0, mostSignificantByteFirst); } -TagLib::uint ByteVector::toUInt(uint offset, bool mostSignificantByteFirst) const +unsigned int ByteVector::toUInt(unsigned int offset, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, mostSignificantByteFirst); + return toNumber(*this, offset, mostSignificantByteFirst); } -TagLib::uint ByteVector::toUInt(uint offset, uint length, bool mostSignificantByteFirst) const +unsigned int ByteVector::toUInt(unsigned int offset, unsigned int length, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, length, mostSignificantByteFirst); + return toNumber(*this, offset, length, mostSignificantByteFirst); } short ByteVector::toShort(bool mostSignificantByteFirst) const @@ -798,7 +733,7 @@ return toNumber(*this, 0, mostSignificantByteFirst); } -short ByteVector::toShort(uint offset, bool mostSignificantByteFirst) const +short ByteVector::toShort(unsigned int offset, bool mostSignificantByteFirst) const { return toNumber(*this, offset, mostSignificantByteFirst); } @@ -808,7 +743,7 @@ return toNumber(*this, 0, mostSignificantByteFirst); } -unsigned short ByteVector::toUShort(uint offset, bool mostSignificantByteFirst) const +unsigned short ByteVector::toUShort(unsigned int offset, bool mostSignificantByteFirst) const { return toNumber(*this, offset, mostSignificantByteFirst); } @@ -818,29 +753,29 @@ return toNumber(*this, 0, mostSignificantByteFirst); } -long long ByteVector::toLongLong(uint offset, bool mostSignificantByteFirst) const +long long ByteVector::toLongLong(unsigned int offset, bool mostSignificantByteFirst) const { return toNumber(*this, offset, mostSignificantByteFirst); } float ByteVector::toFloat32LE(size_t offset) const { - return toFloat(*this, offset); + return toFloat(*this, offset); } float ByteVector::toFloat32BE(size_t offset) const { - return toFloat(*this, offset); + return toFloat(*this, offset); } double ByteVector::toFloat64LE(size_t offset) const { - return toFloat(*this, offset); + return toFloat(*this, offset); } double ByteVector::toFloat64BE(size_t offset) const { - return toFloat(*this, offset); + return toFloat(*this, offset); } long double ByteVector::toFloat80LE(size_t offset) const @@ -855,13 +790,13 @@ const char &ByteVector::operator[](int index) const { - return d->data->data[d->offset + index]; + return (*d->data)[d->offset + index]; } char &ByteVector::operator[](int index) { detach(); - return d->data->data[d->offset + index]; + return (*d->data)[d->offset + index]; } bool ByteVector::operator==(const ByteVector &v) const @@ -874,7 +809,7 @@ bool ByteVector::operator!=(const ByteVector &v) const { - return !operator==(v); + return !(*this == v); } bool ByteVector::operator==(const char *s) const @@ -887,7 +822,7 @@ bool ByteVector::operator!=(const char *s) const { - return !operator==(s); + return !(*this == s); } bool ByteVector::operator<(const ByteVector &v) const @@ -901,7 +836,7 @@ bool ByteVector::operator>(const ByteVector &v) const { - return v < *this; + return (v < *this); } ByteVector ByteVector::operator+(const ByteVector &v) const @@ -913,35 +848,37 @@ ByteVector &ByteVector::operator=(const ByteVector &v) { - if(&v == this) - return *this; - - if(d->deref()) - delete d; - - d = v.d; - d->ref(); + ByteVector(v).swap(*this); return *this; } ByteVector &ByteVector::operator=(char c) { - *this = ByteVector(c); + ByteVector(c).swap(*this); return *this; } ByteVector &ByteVector::operator=(const char *data) { - *this = ByteVector(data); + ByteVector(data).swap(*this); return *this; } +void ByteVector::swap(ByteVector &v) +{ + using std::swap; + + swap(d, v.d); +} + ByteVector ByteVector::toHex() const { + static const char hexTable[17] = "0123456789abcdef"; + ByteVector encoded(size() * 2); char *p = encoded.data(); - for(uint i = 0; i < size(); i++) { + for(unsigned int i = 0; i < size(); i++) { unsigned char c = data()[i]; *p++ = hexTable[(c >> 4) & 0x0F]; *p++ = hexTable[(c ) & 0x0F]; @@ -950,21 +887,134 @@ return encoded; } +ByteVector ByteVector::fromBase64(const ByteVector & input) +{ + static const unsigned char base64[256] = { + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x3e,0x80,0x80,0x80,0x3f, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x80,0x80,0x80,0x80,0x80, + 0x80,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 + }; + + unsigned int len = input.size(); + + ByteVector output(len); + + const unsigned char * src = (const unsigned char*) input.data(); + unsigned char * dst = (unsigned char*) output.data(); + + while(4 <= len) { + + // Check invalid character + if(base64[src[0]] == 0x80) + break; + + // Check invalid character + if(base64[src[1]] == 0x80) + break; + + // Decode first byte + *dst++ = ((base64[src[0]] << 2) & 0xfc) | ((base64[src[1]] >> 4) & 0x03); + + if(src[2] != '=') { + + // Check invalid character + if(base64[src[2]] == 0x80) + break; + + // Decode second byte + *dst++ = ((base64[src[1]] & 0x0f) << 4) | ((base64[src[2]] >> 2) & 0x0f); + + if(src[3] != '=') { + + // Check invalid character + if(base64[src[3]] == 0x80) + break; + + // Decode third byte + *dst++ = ((base64[src[2]] & 0x03) << 6) | (base64[src[3]] & 0x3f); + } + else { + // assume end of data + len -= 4; + break; + } + } + else { + // assume end of data + len -= 4; + break; + } + src += 4; + len -= 4; + } + + // Only return output if we processed all bytes + if(len == 0) { + output.resize(dst - (unsigned char*) output.data()); + return output; + } + return ByteVector(); +} + +ByteVector ByteVector::toBase64() const +{ + static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if(!isEmpty()) { + unsigned int len = size(); + ByteVector output(4 * ((len - 1) / 3 + 1)); // note roundup + + const char * src = data(); + char * dst = output.data(); + while(3 <= len) { + *dst++ = alphabet[(src[0] >> 2) & 0x3f]; + *dst++ = alphabet[((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0f)]; + *dst++ = alphabet[((src[1] & 0x0f) << 2) | ((src[2] >> 6) & 0x03)]; + *dst++ = alphabet[src[2] & 0x3f]; + src += 3; + len -= 3; + } + if(len) { + *dst++ = alphabet[(src[0] >> 2) & 0x3f]; + if(len>1) { + *dst++ = alphabet[((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0f)]; + *dst++ = alphabet[((src[1] & 0x0f) << 2)]; + } + else { + *dst++ = alphabet[(src[0] & 0x03) << 4]; + *dst++ = '='; + } + *dst++ = '='; + } + return output; + } + return ByteVector(); +} + + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void ByteVector::detach() { - if(d->data->count() > 1) { - d->data->deref(); - d->data = new DataPrivate(d->data->data, d->offset, d->length); - d->offset = 0; - } - - if(d->count() > 1) { - d->deref(); - d = new ByteVectorPrivate(d->data->data, d->offset, d->length); + if(d->counter->count() > 1) { + if(!isEmpty()) + ByteVector(&d->data->front() + d->offset, d->length).swap(*this); + else + ByteVector().swap(*this); } } } @@ -975,7 +1025,7 @@ std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v) { - for(TagLib::uint i = 0; i < v.size(); i++) + for(unsigned int i = 0; i < v.size(); i++) s << v[i]; return s; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevector.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevector.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevector.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevector.h 2016-07-19 15:25:23.000000000 +0000 @@ -61,7 +61,7 @@ * Construct a vector of size \a size with all values set to \a value by * default. */ - ByteVector(uint size, char value = 0); + ByteVector(unsigned int size, char value = 0); /*! * Constructs a byte vector that is a copy of \a v. @@ -71,7 +71,7 @@ /*! * Constructs a byte vector that is a copy of \a v. */ - ByteVector(const ByteVector &v, uint offset, uint length); + ByteVector(const ByteVector &v, unsigned int offset, unsigned int length); /*! * Constructs a byte vector that contains \a c. @@ -81,7 +81,7 @@ /*! * Constructs a byte vector that copies \a data for up to \a length bytes. */ - ByteVector(const char *data, uint length); + ByteVector(const char *data, unsigned int length); /*! * Constructs a byte vector that copies \a data up to the first null @@ -100,7 +100,7 @@ /*! * Sets the data for the byte array using the first \a length bytes of \a data */ - ByteVector &setData(const char *data, uint length); + ByteVector &setData(const char *data, unsigned int length); /*! * Sets the data for the byte array copies \a data up to the first null @@ -127,13 +127,13 @@ * for \a length bytes. If \a length is not specified it will return the bytes * from \a index to the end of the vector. */ - ByteVector mid(uint index, uint length = 0xffffffff) const; + ByteVector mid(unsigned int index, unsigned int length = 0xffffffff) const; /*! * This essentially performs the same as operator[](), but instead of causing * a runtime error if the index is out of bounds, it will return a null byte. */ - char at(uint index) const; + char at(unsigned int index) const; /*! * Searches the ByteVector for \a pattern starting at \a offset and returns @@ -141,7 +141,7 @@ * specified the pattern will only be matched if it starts on a byte divisible * by \a byteAlign (starting from \a offset). */ - int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; + int find(const ByteVector &pattern, unsigned int offset = 0, int byteAlign = 1) const; /*! * Searches the char for \a c starting at \a offset and returns @@ -149,7 +149,7 @@ * specified the pattern will only be matched if it starts on a byte divisible * by \a byteAlign (starting from \a offset). */ - int find(char c, uint offset = 0, int byteAlign = 1) const; + int find(char c, unsigned int offset = 0, int byteAlign = 1) const; /*! * Searches the ByteVector for \a pattern starting from either the end of the @@ -157,7 +157,7 @@ * not found. If \a byteAlign is specified the pattern will only be matched * if it starts on a byte divisible by \a byteAlign (starting from \a offset). */ - int rfind(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; + int rfind(const ByteVector &pattern, unsigned int offset = 0, int byteAlign = 1) const; /*! * Checks to see if the vector contains the \a pattern starting at position @@ -166,7 +166,8 @@ * specify to only check for the first \a patternLength bytes of \a pattern with * the \a patternLength argument. */ - bool containsAt(const ByteVector &pattern, uint offset, uint patternOffset = 0, uint patternLength = 0xffffffff) const; + bool containsAt(const ByteVector &pattern, unsigned int offset, + unsigned int patternOffset = 0, unsigned int patternLength = 0xffffffff) const; /*! * Returns true if the vector starts with \a pattern. @@ -179,6 +180,12 @@ bool endsWith(const ByteVector &pattern) const; /*! + * Replaces \a oldByte with \a newByte and returns a reference to the + * ByteVector after the operation. This \e does modify the vector. + */ + ByteVector &replace(char oldByte, char newByte); + + /*! * Replaces \a pattern with \a with and returns a reference to the ByteVector * after the operation. This \e does modify the vector. */ @@ -202,6 +209,11 @@ ByteVector &append(const ByteVector &v); /*! + * Appends \a c to the end of the ByteVector. + */ + ByteVector &append(char c); + + /*! * Clears the data. */ ByteVector &clear(); @@ -209,14 +221,14 @@ /*! * Returns the size of the array. */ - uint size() const; + unsigned int size() const; /*! * Resize the vector to \a size. If the vector is currently less than * \a size, pad the remaining spaces with \a padding. Returns a reference * to the resized vector. */ - ByteVector &resize(uint size, char padding = 0); + ByteVector &resize(unsigned int size, char padding = 0); /*! * Returns an Iterator that points to the front of the vector. @@ -261,9 +273,14 @@ /*! * Returns true if the vector is null. * - * \note A vector may be empty without being null. + * \note A vector may be empty without being null. So do not use this + * method to check if the vector is empty. + * * \see isEmpty() + * + * \deprecated */ + // BIC: remove bool isNull() const; /*! @@ -280,7 +297,7 @@ * \note This uses an uncommon variant of CRC32 specializes in Ogg. */ // BIC: Remove or make generic. - uint checksum() const; + unsigned int checksum() const; /*! * Converts the first 4 bytes of the vector to an unsigned integer. @@ -292,7 +309,7 @@ * * \see fromUInt() */ - uint toUInt(bool mostSignificantByteFirst = true) const; + unsigned int toUInt(bool mostSignificantByteFirst = true) const; /*! * Converts the 4 bytes at \a offset of the vector to an unsigned integer. @@ -304,7 +321,7 @@ * * \see fromUInt() */ - uint toUInt(uint offset, bool mostSignificantByteFirst = true) const; + unsigned int toUInt(unsigned int offset, bool mostSignificantByteFirst = true) const; /*! * Converts the \a length bytes at \a offset of the vector to an unsigned @@ -317,7 +334,8 @@ * * \see fromUInt() */ - uint toUInt(uint offset, uint length, bool mostSignificantByteFirst = true) const; + unsigned int toUInt(unsigned int offset, unsigned int length, + bool mostSignificantByteFirst = true) const; /*! * Converts the first 2 bytes of the vector to a (signed) short. @@ -339,7 +357,7 @@ * * \see fromShort() */ - short toShort(uint offset, bool mostSignificantByteFirst = true) const; + short toShort(unsigned int offset, bool mostSignificantByteFirst = true) const; /*! * Converts the first 2 bytes of the vector to a unsigned short. @@ -361,7 +379,7 @@ * * \see fromShort() */ - unsigned short toUShort(uint offset, bool mostSignificantByteFirst = true) const; + unsigned short toUShort(unsigned int offset, bool mostSignificantByteFirst = true) const; /*! * Converts the first 8 bytes of the vector to a (signed) long long. @@ -385,7 +403,7 @@ * * \see fromUInt() */ - long long toLongLong(uint offset, bool mostSignificantByteFirst = true) const; + long long toLongLong(unsigned int offset, bool mostSignificantByteFirst = true) const; /* * Converts the 4 bytes at \a offset of the vector to a float as an IEEE754 @@ -436,7 +454,7 @@ * * \see toUInt() */ - static ByteVector fromUInt(uint value, bool mostSignificantByteFirst = true); + static ByteVector fromUInt(unsigned int value, bool mostSignificantByteFirst = true); /*! * Creates a 2 byte ByteVector based on \a value. If @@ -494,7 +512,7 @@ /*! * Returns a ByteVector based on the CString \a s. */ - static ByteVector fromCString(const char *s, uint length = 0xffffffff); + static ByteVector fromCString(const char *s, unsigned int length = 0xffffffff); /*! * Returns a const reference to the byte at \a index. @@ -563,9 +581,20 @@ ByteVector &operator=(const char *data); /*! + * Exchanges the content of the ByteVector by the content of \a v. + */ + void swap(ByteVector &v); + + /*! * A static, empty ByteVector which is convenient and fast (since returning * an empty or "null" value does not require instantiating a new ByteVector). + * + * \warning Do not modify this variable. It will mess up the internal state + * of TagLib. + * + * \deprecated */ + // BIC: remove static ByteVector null; /*! @@ -573,6 +602,16 @@ */ ByteVector toHex() const; + /*! + * Returns a base64 encoded copy of the byte vector + */ + ByteVector toBase64() const; + + /*! + * Decodes the base64 encoded byte vector. + */ + static ByteVector fromBase64(const ByteVector &); + protected: /* * If this ByteVector is being shared via implicit sharing, do a deep copy diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevectorlist.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevectorlist.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevectorlist.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevectorlist.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -47,7 +47,7 @@ { ByteVectorList l; - uint previousOffset = 0; + unsigned int previousOffset = 0; for(int offset = v.find(pattern, 0, byteAlign); offset != -1 && (max == 0 || max > int(l.size()) + 1); offset = v.find(pattern, offset + pattern.size(), byteAlign)) @@ -55,7 +55,7 @@ if(offset - previousOffset >= 1) l.append(v.mid(previousOffset, offset - previousOffset)); else - l.append(ByteVector::null); + l.append(ByteVector()); previousOffset = offset + pattern.size(); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevectorstream.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevectorstream.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevectorstream.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevectorstream.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -68,10 +68,10 @@ return FileName(""); // XXX do we need a name? } -ByteVector ByteVectorStream::readBlock(ulong length) +ByteVector ByteVectorStream::readBlock(unsigned long length) { if(length == 0) - return ByteVector::null; + return ByteVector(); ByteVector v = d->data.mid(d->position, length); d->position += v.size(); @@ -80,7 +80,7 @@ void ByteVectorStream::writeBlock(const ByteVector &data) { - uint size = data.size(); + unsigned int size = data.size(); if(long(d->position + size) > length()) { truncate(d->position + size); } @@ -88,7 +88,7 @@ d->position += size; } -void ByteVectorStream::insert(const ByteVector &data, ulong start, ulong replace) +void ByteVectorStream::insert(const ByteVector &data, unsigned long start, unsigned long replace) { long sizeDiff = data.size() - replace; if(sizeDiff < 0) { @@ -96,20 +96,20 @@ } else if(sizeDiff > 0) { truncate(length() + sizeDiff); - ulong readPosition = start + replace; - ulong writePosition = start + data.size(); + unsigned long readPosition = start + replace; + unsigned long writePosition = start + data.size(); memmove(d->data.data() + writePosition, d->data.data() + readPosition, length() - sizeDiff - readPosition); } seek(start); writeBlock(data); } -void ByteVectorStream::removeBlock(ulong start, ulong length) +void ByteVectorStream::removeBlock(unsigned long start, unsigned long length) { - ulong readPosition = start + length; - ulong writePosition = start; - if(readPosition < ulong(ByteVectorStream::length())) { - ulong bytesToMove = ByteVectorStream::length() - readPosition; + unsigned long readPosition = start + length; + unsigned long writePosition = start; + if(readPosition < static_cast(ByteVectorStream::length())) { + unsigned long bytesToMove = ByteVectorStream::length() - readPosition; memmove(d->data.data() + writePosition, d->data.data() + readPosition, bytesToMove); writePosition += bytesToMove; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevectorstream.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevectorstream.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tbytevectorstream.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tbytevectorstream.h 2016-07-19 15:25:23.000000000 +0000 @@ -61,7 +61,7 @@ /*! * Reads a block of size \a length at the current get pointer. */ - ByteVector readBlock(ulong length); + ByteVector readBlock(unsigned long length); /*! * Attempts to write the block \a data at the current get pointer. If the @@ -81,7 +81,7 @@ * \note This method is slow since it requires rewriting all of the file * after the insertion point. */ - void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); + void insert(const ByteVector &data, unsigned long start = 0, unsigned long replace = 0); /*! * Removes a block of the file starting a \a start and continuing for @@ -90,7 +90,7 @@ * \note This method is slow since it involves rewriting all of the file * after the removed portion. */ - void removeBlock(ulong start = 0, ulong length = 0); + void removeBlock(unsigned long start = 0, unsigned long length = 0); /*! * Returns true if the file is read only (or if the file can not be opened). diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tfile.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -224,7 +224,7 @@ return tag()->setProperties(properties); } -ByteVector File::readBlock(ulong length) +ByteVector File::readBlock(unsigned long length) { return d->stream->readBlock(length); } @@ -289,7 +289,7 @@ } } - if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(bufferSize()) > beforePreviousPartialMatch) { + if(!before.isEmpty() && beforePreviousPartialMatch >= 0 && int(bufferSize()) > beforePreviousPartialMatch) { const int beforeOffset = (bufferSize() - beforePreviousPartialMatch); if(buffer.containsAt(before, 0, beforeOffset)) { seek(originalPosition); @@ -305,7 +305,7 @@ return bufferOffset + location; } - if(!before.isNull() && buffer.find(before) >= 0) { + if(!before.isEmpty() && buffer.find(before) >= 0) { seek(originalPosition); return -1; } @@ -314,7 +314,7 @@ previousPartialMatch = buffer.endsWithPartialMatch(pattern); - if(!before.isNull()) + if(!before.isEmpty()) beforePreviousPartialMatch = buffer.endsWithPartialMatch(before); bufferOffset += bufferSize(); @@ -387,7 +387,7 @@ return bufferOffset + location; } - if(!before.isNull() && buffer.find(before) >= 0) { + if(!before.isEmpty() && buffer.find(before) >= 0) { seek(originalPosition); return -1; } @@ -404,12 +404,12 @@ return -1; } -void File::insert(const ByteVector &data, ulong start, ulong replace) +void File::insert(const ByteVector &data, unsigned long start, unsigned long replace) { d->stream->insert(data, start, replace); } -void File::removeBlock(ulong start, ulong length) +void File::removeBlock(unsigned long start, unsigned long length) { d->stream->removeBlock(start, length); } @@ -488,7 +488,7 @@ // protected members //////////////////////////////////////////////////////////////////////////////// -TagLib::uint File::bufferSize() +unsigned int File::bufferSize() { return 1024; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tfile.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tfile.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -138,7 +138,7 @@ /*! * Reads a block of size \a length at the current get pointer. */ - ByteVector readBlock(ulong length); + ByteVector readBlock(unsigned long length); /*! * Attempts to write the block \a data at the current get pointer. If the @@ -165,7 +165,7 @@ */ long find(const ByteVector &pattern, long fromOffset = 0, - const ByteVector &before = ByteVector::null); + const ByteVector &before = ByteVector()); /*! * Returns the offset in the file that \a pattern occurs at or -1 if it can @@ -181,7 +181,7 @@ */ long rfind(const ByteVector &pattern, long fromOffset = 0, - const ByteVector &before = ByteVector::null); + const ByteVector &before = ByteVector()); /*! * Insert \a data at position \a start in the file overwriting \a replace @@ -190,7 +190,7 @@ * \note This method is slow since it requires rewriting all of the file * after the insertion point. */ - void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); + void insert(const ByteVector &data, unsigned long start = 0, unsigned long replace = 0); /*! * Removes a block of the file starting a \a start and continuing for @@ -199,7 +199,7 @@ * \note This method is slow since it involves rewriting all of the file * after the removed portion. */ - void removeBlock(ulong start = 0, ulong length = 0); + void removeBlock(unsigned long start = 0, unsigned long length = 0); /*! * Returns true if the file is read only (or if the file can not be opened). @@ -291,7 +291,7 @@ /*! * Returns the buffer size that is used for internal buffering. */ - static uint bufferSize(); + static unsigned int bufferSize(); private: File(const File &); diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tfilestream.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tfilestream.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tfilestream.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tfilestream.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -47,7 +47,7 @@ const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE; - inline FileHandle openFile(const FileName &path, bool readOnly) + FileHandle openFile(const FileName &path, bool readOnly) { const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); @@ -59,12 +59,12 @@ return InvalidFileHandle; } - inline void closeFile(FileHandle file) + void closeFile(FileHandle file) { CloseHandle(file); } - inline size_t readFile(FileHandle file, ByteVector &buffer) + size_t readFile(FileHandle file, ByteVector &buffer) { DWORD length; if(ReadFile(file, buffer.data(), static_cast(buffer.size()), &length, NULL)) @@ -73,7 +73,7 @@ return 0; } - inline size_t writeFile(FileHandle file, const ByteVector &buffer) + size_t writeFile(FileHandle file, const ByteVector &buffer) { DWORD length; if(WriteFile(file, buffer.data(), static_cast(buffer.size()), &length, NULL)) @@ -94,22 +94,22 @@ const FileHandle InvalidFileHandle = 0; - inline FileHandle openFile(const FileName &path, bool readOnly) + FileHandle openFile(const FileName &path, bool readOnly) { return fopen(path, readOnly ? "rb" : "rb+"); } - inline void closeFile(FileHandle file) + void closeFile(FileHandle file) { fclose(file); } - inline size_t readFile(FileHandle file, ByteVector &buffer) + size_t readFile(FileHandle file, ByteVector &buffer) { return fread(buffer.data(), sizeof(char), buffer.size(), file); } - inline size_t writeFile(FileHandle file, const ByteVector &buffer) + size_t writeFile(FileHandle file, const ByteVector &buffer) { return fwrite(buffer.data(), sizeof(char), buffer.size(), file); } @@ -172,24 +172,24 @@ return d->name; } -ByteVector FileStream::readBlock(ulong length) +ByteVector FileStream::readBlock(unsigned long length) { if(!isOpen()) { debug("FileStream::readBlock() -- invalid file."); - return ByteVector::null; + return ByteVector(); } if(length == 0) - return ByteVector::null; + return ByteVector(); - const ulong streamLength = static_cast(FileStream::length()); + const unsigned long streamLength = static_cast(FileStream::length()); if(length > bufferSize() && length > streamLength) length = streamLength; - ByteVector buffer(static_cast(length)); + ByteVector buffer(static_cast(length)); const size_t count = readFile(d->file, buffer); - buffer.resize(static_cast(count)); + buffer.resize(static_cast(count)); return buffer; } @@ -209,7 +209,7 @@ writeFile(d->file, data); } -void FileStream::insert(const ByteVector &data, ulong start, ulong replace) +void FileStream::insert(const ByteVector &data, unsigned long start, unsigned long replace) { if(!isOpen()) { debug("FileStream::insert() -- invalid file."); @@ -243,7 +243,7 @@ // the *differnce* in the tag sizes. We want to avoid overwriting parts // that aren't yet in memory, so this is necessary. - ulong bufferLength = bufferSize(); + unsigned long bufferLength = bufferSize(); while(data.size() - replace > bufferLength) bufferLength += bufferSize(); @@ -254,7 +254,7 @@ long writePosition = start; ByteVector buffer = data; - ByteVector aboutToOverwrite(static_cast(bufferLength)); + ByteVector aboutToOverwrite(static_cast(bufferLength)); while(true) { @@ -291,19 +291,19 @@ } } -void FileStream::removeBlock(ulong start, ulong length) +void FileStream::removeBlock(unsigned long start, unsigned long length) { if(!isOpen()) { debug("FileStream::removeBlock() -- invalid file."); return; } - ulong bufferLength = bufferSize(); + unsigned long bufferLength = bufferSize(); long readPosition = start + length; long writePosition = start; - ByteVector buffer(static_cast(bufferLength)); + ByteVector buffer(static_cast(bufferLength)); for(size_t bytesRead = -1; bytesRead != 0;) { @@ -490,7 +490,7 @@ #endif } -TagLib::uint FileStream::bufferSize() +unsigned int FileStream::bufferSize() { return 1024; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tfilestream.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tfilestream.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tfilestream.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tfilestream.h 2016-07-19 15:25:23.000000000 +0000 @@ -67,7 +67,7 @@ /*! * Reads a block of size \a length at the current get pointer. */ - ByteVector readBlock(ulong length); + ByteVector readBlock(unsigned long length); /*! * Attempts to write the block \a data at the current get pointer. If the @@ -87,7 +87,7 @@ * \note This method is slow since it requires rewriting all of the file * after the insertion point. */ - void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); + void insert(const ByteVector &data, unsigned long start = 0, unsigned long replace = 0); /*! * Removes a block of the file starting a \a start and continuing for @@ -96,7 +96,7 @@ * \note This method is slow since it involves rewriting all of the file * after the removed portion. */ - void removeBlock(ulong start = 0, ulong length = 0); + void removeBlock(unsigned long start = 0, unsigned long length = 0); /*! * Returns true if the file is read only (or if the file can not be opened). @@ -142,7 +142,7 @@ /*! * Returns the buffer size that is used for internal buffering. */ - static uint bufferSize(); + static unsigned int bufferSize(); private: class FileStreamPrivate; diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tiostream.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tiostream.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tiostream.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tiostream.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -33,10 +33,10 @@ # include "tdebug.h" # include -namespace +namespace { // Check if the running system has CreateFileW() function. - // Windows9x systems don't have CreateFileW() or can't accept Unicode file names. + // Windows9x systems don't have CreateFileW() or can't accept Unicode file names. bool supportsUnicode() { @@ -49,11 +49,11 @@ } // Indicates whether the system supports Unicode file names. - - const bool SystemSupportsUnicode = supportsUnicode(); + + const bool SystemSupportsUnicode = supportsUnicode(); // Converts a UTF-16 string into a local encoding. - // This function should only be used in Windows9x systems which don't support + // This function should only be used in Windows9x systems which don't support // Unicode file names. std::string unicodeToAnsi(const wchar_t *wstr) @@ -76,52 +76,52 @@ // If WinNT, stores a Unicode string into m_wname directly. // If Win9x, converts and stores it into m_name to avoid calling Unicode version functions. -FileName::FileName(const wchar_t *name) +FileName::FileName(const wchar_t *name) : m_name (SystemSupportsUnicode ? "" : unicodeToAnsi(name)) , m_wname(SystemSupportsUnicode ? name : L"") { } -FileName::FileName(const char *name) - : m_name(name) +FileName::FileName(const char *name) + : m_name(name) { } -FileName::FileName(const FileName &name) - : m_name (name.m_name) +FileName::FileName(const FileName &name) + : m_name (name.m_name) , m_wname(name.m_wname) { } -FileName::operator const wchar_t *() const -{ - return m_wname.c_str(); +FileName::operator const wchar_t *() const +{ + return m_wname.c_str(); } -FileName::operator const char *() const -{ - return m_name.c_str(); +FileName::operator const char *() const +{ + return m_name.c_str(); } -const std::wstring &FileName::wstr() const -{ - return m_wname; +const std::wstring &FileName::wstr() const +{ + return m_wname; } -const std::string &FileName::str() const -{ - return m_name; -} +const std::string &FileName::str() const +{ + return m_name; +} String FileName::toString() const { if(!m_wname.empty()) { return String(m_wname); - } + } else if(!m_name.empty()) { const int len = MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, NULL, 0); if(len == 0) - return String::null; + return String(); std::vector buf(len); MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, &buf[0], len); @@ -129,7 +129,7 @@ return String(&buf[0]); } else { - return String::null; + return String(); } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tiostream.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tiostream.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tiostream.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tiostream.h 2016-07-19 15:25:23.000000000 +0000 @@ -89,7 +89,7 @@ /*! * Reads a block of size \a length at the current get pointer. */ - virtual ByteVector readBlock(ulong length) = 0; + virtual ByteVector readBlock(unsigned long length) = 0; /*! * Attempts to write the block \a data at the current get pointer. If the @@ -109,7 +109,8 @@ * \note This method is slow since it requires rewriting all of the file * after the insertion point. */ - virtual void insert(const ByteVector &data, ulong start = 0, ulong replace = 0) = 0; + virtual void insert(const ByteVector &data, + unsigned long start = 0, unsigned long replace = 0) = 0; /*! * Removes a block of the file starting a \a start and continuing for @@ -118,7 +119,7 @@ * \note This method is slow since it involves rewriting all of the file * after the removed portion. */ - virtual void removeBlock(ulong start = 0, ulong length = 0) = 0; + virtual void removeBlock(unsigned long start = 0, unsigned long length = 0) = 0; /*! * Returns true if the file is read only (or if the file can not be opened). diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tlist.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tlist.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tlist.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tlist.h 2016-07-19 15:25:23.000000000 +0000 @@ -146,8 +146,16 @@ /*! * Returns the number of elements in the list. + * + * \see isEmpty() + */ + unsigned int size() const; + + /*! + * Returns whether or not the list is empty. + * + * \see size() */ - uint size() const; bool isEmpty() const; /*! @@ -205,14 +213,14 @@ * * \warning This method is slow. Use iterators to loop through the list. */ - T &operator[](uint i); + T &operator[](unsigned int i); /*! * Returns a const reference to item \a i in the list. * * \warning This method is slow. Use iterators to loop through the list. */ - const T &operator[](uint i) const; + const T &operator[](unsigned int i) const; /*! * Make a shallow, implicitly shared, copy of \a l. Because this is diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tlist.tcc clementine-1.3.1-218/3rdparty/taglib/toolkit/tlist.tcc --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tlist.tcc 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tlist.tcc 2016-07-19 15:25:23.000000000 +0000 @@ -194,7 +194,7 @@ } template -TagLib::uint List::size() const +unsigned int List::size() const { return d->list.size(); } @@ -263,7 +263,7 @@ } template -T &List::operator[](uint i) +T &List::operator[](unsigned int i) { Iterator it = d->list.begin(); std::advance(it, i); @@ -272,7 +272,7 @@ } template -const T &List::operator[](uint i) const +const T &List::operator[](unsigned int i) const { ConstIterator it = d->list.begin(); std::advance(it, i); diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tmap.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tmap.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tmap.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tmap.h 2016-07-19 15:25:23.000000000 +0000 @@ -119,7 +119,7 @@ * * \see isEmpty() */ - uint size() const; + unsigned int size() const; /*! * Returns true if the map is empty. diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tmap.tcc clementine-1.3.1-218/3rdparty/taglib/toolkit/tmap.tcc --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tmap.tcc 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tmap.tcc 2016-07-19 15:25:23.000000000 +0000 @@ -150,7 +150,7 @@ } template -TagLib::uint Map::size() const +unsigned int Map::size() const { return d->map.size(); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tpropertymap.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tpropertymap.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tpropertymap.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tpropertymap.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "tpropertymap.h" using namespace TagLib; @@ -35,7 +40,7 @@ { for(SimplePropertyMap::ConstIterator it = m.begin(); it != m.end(); ++it){ String key = it->first.upper(); - if(!key.isNull()) + if(!key.isEmpty()) insert(it->first, it->second); else unsupported.append(it->first); @@ -144,7 +149,8 @@ String PropertyMap::toString() const { - String ret = ""; + String ret; + for(ConstIterator it = begin(); it != end(); ++it) ret += it->first+"="+it->second.toString(", ") + "\n"; if(!unsupported.isEmpty()) diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tpropertymap.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tpropertymap.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tpropertymap.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tpropertymap.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_PROPERTYMAP_H_ diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/trefcounter.h clementine-1.3.1-218/3rdparty/taglib/toolkit/trefcounter.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/trefcounter.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/trefcounter.h 2016-07-19 15:25:23.000000000 +0000 @@ -102,7 +102,7 @@ bool deref() { return ! --refCount; } int count() { return refCount; } private: - uint refCount; + unsigned int refCount; #endif }; diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tstring.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tstring.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tstring.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tstring.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -25,17 +25,9 @@ // This class assumes that std::basic_string has a contiguous and null-terminated buffer. -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "tstring.h" -#include "tdebug.h" -#include "tstringlist.h" -#include "trefcounter.h" -#include "tutils.h" - #include +#include +#include #include #include @@ -45,12 +37,18 @@ # include "unicode.h" #endif +#include +#include +#include +#include + +#include "tstring.h" + namespace { using namespace TagLib; - inline size_t UTF16toUTF8( - const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) + size_t UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) { size_t len = 0; @@ -82,8 +80,7 @@ return len; } - inline size_t UTF8toUTF16( - const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) + size_t UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) { size_t len = 0; @@ -114,30 +111,128 @@ return len; } -} -namespace TagLib { + // Returns the native format of std::wstring. + String::Type wcharByteOrder() + { + if(Utils::systemByteOrder() == Utils::LittleEndian) + return String::UTF16LE; + else + return String::UTF16BE; + } -class String::StringPrivate : public RefCounter -{ -public: - StringPrivate() - : RefCounter() + // Converts a Latin-1 string into UTF-16(without BOM/CPU byte order) + // and copies it to the internal buffer. + void copyFromLatin1(std::wstring &data, const char *s, size_t length) { + data.resize(length); + + for(size_t i = 0; i < length; ++i) + data[i] = static_cast(s[i]); } - StringPrivate(const wstring &s) - : RefCounter() - , data(s) + // Converts a UTF-8 string into UTF-16(without BOM/CPU byte order) + // and copies it to the internal buffer. + void copyFromUTF8(std::wstring &data, const char *s, size_t length) { + data.resize(length); + + if(length > 0) { + const size_t len = UTF8toUTF16(s, length, &data[0], data.size()); + data.resize(len); + } } - StringPrivate(uint n, wchar_t c) - : RefCounter() - , data(static_cast(n), c) + // Converts a UTF-16 (with BOM), UTF-16LE or UTF16-BE string into + // UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. + void copyFromUTF16(std::wstring &data, const wchar_t *s, size_t length, String::Type t) { + bool swap; + if(t == String::UTF16) { + if(length >= 1 && s[0] == 0xfeff) + swap = false; // Same as CPU endian. No need to swap bytes. + else if(length >= 1 && s[0] == 0xfffe) + swap = true; // Not same as CPU endian. Need to swap bytes. + else { + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; + } + + s++; + length--; + } + else { + swap = (t != wcharByteOrder()); + } + + data.resize(length); + if(length > 0) { + if(swap) { + for(size_t i = 0; i < length; ++i) + data[i] = Utils::byteSwap(static_cast(s[i])); + } + else { + ::wmemcpy(&data[0], s, length); + } + } } + // Converts a UTF-16 (with BOM), UTF-16LE or UTF16-BE string into + // UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. + void copyFromUTF16(std::wstring &data, const char *s, size_t length, String::Type t) + { + bool swap; + if(t == String::UTF16) { + if(length < 2) { + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; + } + + // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. + unsigned short bom; + ::memcpy(&bom, s, 2); + + if(bom == 0xfeff) + swap = false; // Same as CPU endian. No need to swap bytes. + else if(bom == 0xfffe) + swap = true; // Not same as CPU endian. Need to swap bytes. + else { + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; + } + + s += 2; + length -= 2; + } + else { + swap = (t != wcharByteOrder()); + } + + data.resize(length / 2); + for(size_t i = 0; i < length / 2; ++i) { + unsigned short c; + ::memcpy(&c, s, 2); + if(swap) + c = Utils::byteSwap(c); + + data[i] = static_cast(c); + s += 2; + } + } +} + +namespace TagLib { + +class String::StringPrivate : public RefCounter +{ +public: + StringPrivate() : + RefCounter() {} + + StringPrivate(unsigned int n, wchar_t c) : + RefCounter(), + data(static_cast(n), c) {} + /*! * Stores string in UTF-16. The byte order depends on the CPU endian. */ @@ -152,108 +247,110 @@ String String::null; //////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// -String::String() - : d(new StringPrivate()) +String::String() : + d(new StringPrivate()) { } -String::String(const String &s) - : d(s.d) +String::String(const String &s) : + d(s.d) { d->ref(); } -String::String(const std::string &s, Type t) - : d(new StringPrivate()) +String::String(const std::string &s, Type t) : + d(new StringPrivate()) { if(t == Latin1) - copyFromLatin1(s.c_str(), s.length()); + copyFromLatin1(d->data, s.c_str(), s.length()); else if(t == String::UTF8) - copyFromUTF8(s.c_str(), s.length()); + copyFromUTF8(d->data, s.c_str(), s.length()); else { debug("String::String() -- std::string should not contain UTF16."); } } -String::String(const wstring &s, Type t) - : d(new StringPrivate()) +String::String(const wstring &s, Type t) : + d(new StringPrivate()) { if(t == UTF16 || t == UTF16BE || t == UTF16LE) { // This looks ugly but needed for the compatibility with TagLib1.8. // Should be removed in TabLib2.0. if (t == UTF16BE) - t = WCharByteOrder; + t = wcharByteOrder(); else if (t == UTF16LE) - t = (WCharByteOrder == UTF16LE ? UTF16BE : UTF16LE); + t = (wcharByteOrder() == UTF16LE ? UTF16BE : UTF16LE); - copyFromUTF16(s.c_str(), s.length(), t); + copyFromUTF16(d->data, s.c_str(), s.length(), t); } else { debug("String::String() -- TagLib::wstring should not contain Latin1 or UTF-8."); } } -String::String(const wchar_t *s, Type t) - : d(new StringPrivate()) +String::String(const wchar_t *s, Type t) : + d(new StringPrivate()) { if(t == UTF16 || t == UTF16BE || t == UTF16LE) { // This looks ugly but needed for the compatibility with TagLib1.8. // Should be removed in TabLib2.0. if (t == UTF16BE) - t = WCharByteOrder; + t = wcharByteOrder(); else if (t == UTF16LE) - t = (WCharByteOrder == UTF16LE ? UTF16BE : UTF16LE); + t = (wcharByteOrder() == UTF16LE ? UTF16BE : UTF16LE); - copyFromUTF16(s, ::wcslen(s), t); + copyFromUTF16(d->data, s, ::wcslen(s), t); } else { debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8."); } } -String::String(const char *s, Type t) - : d(new StringPrivate()) +String::String(const char *s, Type t) : + d(new StringPrivate()) { if(t == Latin1) - copyFromLatin1(s, ::strlen(s)); + copyFromLatin1(d->data, s, ::strlen(s)); else if(t == String::UTF8) - copyFromUTF8(s, ::strlen(s)); + copyFromUTF8(d->data, s, ::strlen(s)); else { debug("String::String() -- const char * should not contain UTF16."); } } -String::String(wchar_t c, Type t) - : d(new StringPrivate()) +String::String(wchar_t c, Type t) : + d(new StringPrivate()) { if(t == UTF16 || t == UTF16BE || t == UTF16LE) - copyFromUTF16(&c, 1, t); + copyFromUTF16(d->data, &c, 1, t); else { debug("String::String() -- wchar_t should not contain Latin1 or UTF-8."); } } -String::String(char c, Type t) - : d(new StringPrivate(1, static_cast(c))) +String::String(char c, Type t) : + d(new StringPrivate(1, static_cast(c))) { if(t != Latin1 && t != UTF8) { debug("String::String() -- char should not contain UTF16."); } } -String::String(const ByteVector &v, Type t) - : d(new StringPrivate()) +String::String(const ByteVector &v, Type t) : + d(new StringPrivate()) { if(v.isEmpty()) return; if(t == Latin1) - copyFromLatin1(v.data(), v.size()); + copyFromLatin1(d->data, v.data(), v.size()); else if(t == UTF8) - copyFromUTF8(v.data(), v.size()); + copyFromUTF8(d->data, v.data(), v.size()); else - copyFromUTF16(v.data(), v.size(), t); + copyFromUTF16(d->data, v.data(), v.size(), t); // If we hit a null in the ByteVector, shrink the string again. d->data.resize(::wcslen(d->data.c_str())); @@ -346,7 +443,7 @@ return substr(0, s.length()) == s; } -String String::substr(uint position, uint n) const +String String::substr(unsigned int position, unsigned int n) const { return String(d->data.substr(position, n)); } @@ -358,6 +455,12 @@ return *this; } +String & String::clear() +{ + *this = String(); + return *this; +} + String String::upper() const { String s; @@ -374,19 +477,19 @@ return s; } -TagLib::uint String::size() const +unsigned int String::size() const { return d->data.size(); } -TagLib::uint String::length() const +unsigned int String::length() const { return size(); } bool String::isEmpty() const { - return d->data.size() == 0; + return d->data.empty(); } bool String::isNull() const @@ -420,7 +523,7 @@ return v; } else { - return ByteVector::null; + return ByteVector(); } case UTF16: { @@ -466,7 +569,7 @@ default: { debug("String::data() - Invalid Type value."); - return ByteVector::null; + return ByteVector(); } } } @@ -478,49 +581,30 @@ int String::toInt(bool *ok) const { - int value = 0; - - uint size = d->data.size(); - bool negative = size > 0 && d->data[0] == '-'; - uint start = negative ? 1 : 0; - uint i = start; - - for(; i < size && d->data[i] >= '0' && d->data[i] <= '9'; i++) - value = value * 10 + (d->data[i] - '0'); - - if(negative) - value = value * -1; - - if(ok) - *ok = (size > start && i == size); + const wchar_t *begin = d->data.c_str(); + wchar_t *end; + errno = 0; + const long value = ::wcstol(begin, &end, 10); + + // Has wcstol() consumed the entire string and not overflowed? + if(ok) { + *ok = (errno == 0 && end > begin && *end == L'\0'); + *ok = (*ok && value > INT_MIN && value < INT_MAX); + } - return value; + return static_cast(value); } String String::stripWhiteSpace() const { - wstring::const_iterator begin = d->data.begin(); - wstring::const_iterator end = d->data.end(); - - while(begin != end && - (*begin == '\t' || *begin == '\n' || *begin == '\f' || - *begin == '\r' || *begin == ' ')) - { - ++begin; - } + static const wchar_t *WhiteSpaceChars = L"\t\n\f\r "; - if(begin == end) - return null; + const size_t pos1 = d->data.find_first_not_of(WhiteSpaceChars); + if(pos1 == std::wstring::npos) + return String(); - // There must be at least one non-whitespace character here for us to have - // gotten this far, so we should be safe not doing bounds checking. - - do { - --end; - } while(*end == '\t' || *end == '\n' || - *end == '\f' || *end == '\r' || *end == ' '); - - return String(wstring(begin, end + 1)); + const size_t pos2 = d->data.find_last_not_of(WhiteSpaceChars); + return substr(pos1, pos2 - pos1 + 1); } bool String::isLatin1() const @@ -546,13 +630,13 @@ return Utils::formatString("%d", n); } -TagLib::wchar &String::operator[](int i) +wchar_t &String::operator[](int i) { detach(); return d->data[i]; } -const TagLib::wchar &String::operator[](int i) const +const wchar_t &String::operator[](int i) const { return d->data[i]; } @@ -572,7 +656,7 @@ const wchar_t *p = toCWString(); while(*p != L'\0' || *s != '\0') { - if(*p++ != static_cast(*s++)) + if(*p++ != static_cast(*s++)) return false; } return true; @@ -614,7 +698,7 @@ detach(); for(int i = 0; s[i] != 0; i++) - d->data += uchar(s[i]); + d->data += static_cast(s[i]); return *this; } @@ -630,96 +714,68 @@ { detach(); - d->data += uchar(c); + d->data += static_cast(c); return *this; } String &String::operator=(const String &s) { - if(&s == this) - return *this; - - if(d->deref()) - delete d; - d = s.d; - d->ref(); + String(s).swap(*this); return *this; } String &String::operator=(const std::string &s) { - if(d->deref()) - delete d; - - d = new StringPrivate; - copyFromLatin1(s.c_str(), s.length()); - + String(s).swap(*this); return *this; } String &String::operator=(const wstring &s) { - if(d->deref()) - delete d; - d = new StringPrivate(s); + String(s).swap(*this); return *this; } String &String::operator=(const wchar_t *s) { - if(d->deref()) - delete d; - - d = new StringPrivate(s); + String(s).swap(*this); return *this; } String &String::operator=(char c) { - if(d->deref()) - delete d; - - d = new StringPrivate(1, static_cast(c)); + String(c).swap(*this); return *this; } String &String::operator=(wchar_t c) { - if(d->deref()) - delete d; - - d = new StringPrivate(1, c); + String(c, wcharByteOrder()).swap(*this); return *this; } String &String::operator=(const char *s) { - if(d->deref()) - delete d; - - d = new StringPrivate; - copyFromLatin1(s, ::strlen(s)); - + String(s).swap(*this); return *this; } String &String::operator=(const ByteVector &v) { - if(d->deref()) - delete d; - - d = new StringPrivate; - copyFromLatin1(v.data(), v.size()); + String(v).swap(*this); + return *this; +} - // If we hit a null in the ByteVector, shrink the string again. - d->data.resize(::wcslen(d->data.c_str())); +void String::swap(String &s) +{ + using std::swap; - return *this; + swap(d, s.d); } bool String::operator<(const String &s) const { - return d->data < s.d->data; + return (d->data < s.d->data); } //////////////////////////////////////////////////////////////////////////////// @@ -728,112 +784,13 @@ void String::detach() { - if(d->count() > 1) { - d->deref(); - d = new StringPrivate(d->data); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void String::copyFromLatin1(const char *s, size_t length) -{ - d->data.resize(length); - - for(size_t i = 0; i < length; ++i) - d->data[i] = static_cast(s[i]); -} - -void String::copyFromUTF8(const char *s, size_t length) -{ - d->data.resize(length); - - if(length > 0) { - const size_t len = UTF8toUTF16(s, length, &d->data[0], d->data.size()); - d->data.resize(len); - } -} - -void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) -{ - bool swap; - if(t == UTF16) { - if(length >= 1 && s[0] == 0xfeff) - swap = false; // Same as CPU endian. No need to swap bytes. - else if(length >= 1 && s[0] == 0xfffe) - swap = true; // Not same as CPU endian. Need to swap bytes. - else { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - s++; - length--; - } - else - swap = (t != WCharByteOrder); - - d->data.resize(length); - if(length > 0) { - if(swap) { - for(size_t i = 0; i < length; ++i) - d->data[i] = Utils::byteSwap(static_cast(s[i])); - } - else { - ::wmemcpy(&d->data[0], s, length); - } - } -} - -void String::copyFromUTF16(const char *s, size_t length, Type t) -{ - bool swap; - if(t == UTF16) { - if(length < 2) { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. - ushort bom; - ::memcpy(&bom, s, 2); - - if(bom == 0xfeff) - swap = false; // Same as CPU endian. No need to swap bytes. - else if(bom == 0xfffe) - swap = true; // Not same as CPU endian. Need to swap bytes. - else { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - s += 2; - length -= 2; - } - else - swap = (t != WCharByteOrder); - - d->data.resize(length / 2); - for(size_t i = 0; i < length / 2; ++i) { - ushort c; - ::memcpy(&c, s, 2); - if(swap) - c = Utils::byteSwap(c); - - d->data[i] = static_cast(c); - s += 2; - } + if(d->count() > 1) + String(d->data.c_str()).swap(*this); } - -const String::Type String::WCharByteOrder - = (Utils::systemByteOrder() == Utils::BigEndian) ? String::UTF16BE : String::UTF16LE; - } //////////////////////////////////////////////////////////////////////////////// -// related functions +// related non-member functions //////////////////////////////////////////////////////////////////////////////// const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2) diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tstring.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tstring.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tstring.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tstring.h 2016-07-19 15:25:23.000000000 +0000 @@ -86,8 +86,8 @@ public: #ifndef DO_NOT_DOCUMENT - typedef std::basic_string::iterator Iterator; - typedef std::basic_string::const_iterator ConstIterator; + typedef TagLib::wstring::iterator Iterator; + typedef TagLib::wstring::const_iterator ConstIterator; #endif /** @@ -291,7 +291,7 @@ * Extract a substring from this string starting at \a position and * continuing for \a n characters. */ - String substr(uint position, uint n = 0xffffffff) const; + String substr(unsigned int position, unsigned int n = 0xffffffff) const; /*! * Append \a s to the current string and return a reference to the current @@ -300,6 +300,11 @@ String &append(const String &s); /*! + * Clears the string. + */ + String &clear(); + + /*! * Returns an upper case version of the string. * * \warning This only works for the characters in US-ASCII, i.e. A-Z. @@ -309,12 +314,12 @@ /*! * Returns the size of the string. */ - uint size() const; + unsigned int size() const; /*! * Returns the length of the string. Equivalent to size(). */ - uint length() const; + unsigned int length() const; /*! * Returns true if the string is empty. @@ -327,9 +332,14 @@ * Returns true if this string is null -- i.e. it is a copy of the * String::null string. * - * \note A string can be empty and not null. + * \note A string can be empty and not null. So do not use this method to + * check if the string is empty. + * * \see isEmpty() + * + * \deprecated */ + // BIC: remove bool isNull() const; /*! @@ -385,12 +395,12 @@ /*! * Returns a reference to the character at position \a i. */ - wchar &operator[](int i); + wchar_t &operator[](int i); /*! * Returns a const reference to the character at position \a i. */ - const wchar &operator[](int i) const; + const wchar_t &operator[](int i) const; /*! * Compares each character of the String with each character of \a s and @@ -495,6 +505,11 @@ String &operator=(const ByteVector &v); /*! + * Exchanges the content of the String by the content of \a s. + */ + void swap(String &s); + + /*! * To be able to use this class in a Map, this operator needed to be * implemented. Returns true if \a s is less than this string in a byte-wise * comparison. @@ -503,7 +518,13 @@ /*! * A null string provided for convenience. + * + * \warning Do not modify this variable. It will mess up the internal state + * of TagLib. + * + * \deprecated */ + // BIC: remove static String null; protected: @@ -515,37 +536,6 @@ void detach(); private: - /*! - * Converts a \e Latin-1 string into \e UTF-16(without BOM/CPU byte order) - * and copies it to the internal buffer. - */ - void copyFromLatin1(const char *s, size_t length); - - /*! - * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order) - * and copies it to the internal buffer. - */ - void copyFromUTF8(const char *s, size_t length); - - /*! - * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into - * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. - */ - void copyFromUTF16(const wchar_t *s, size_t length, Type t); - - /*! - * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into - * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. - */ - void copyFromUTF16(const char *s, size_t length, Type t); - - /*! - * Indicates which byte order of UTF-16 is used to store strings internally. - * - * \note \e String::UTF16BE or \e String::UTF16LE - */ - static const Type WCharByteOrder; - class StringPrivate; StringPrivate *d; }; diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tutils.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tutils.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tutils.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tutils.h 2016-07-19 15:25:23.000000000 +0000 @@ -31,10 +31,12 @@ #ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header #ifdef HAVE_CONFIG_H -#include +# include #endif -#if defined(HAVE_MSC_BYTESWAP) +#if defined(HAVE_BOOST_BYTESWAP) +# include +#elif defined(HAVE_MSC_BYTESWAP) # include #elif defined(HAVE_GLIBC_BYTESWAP) # include @@ -53,206 +55,237 @@ { namespace Utils { - - /*! - * Reverses the order of bytes in an 16-bit integer. - */ - inline ushort byteSwap(ushort x) + namespace { -#if defined(HAVE_GCC_BYTESWAP) - return __builtin_bswap16(x); + /*! + * Reverses the order of bytes in an 16-bit integer. + */ + inline unsigned short byteSwap(unsigned short x) + { +#if defined(HAVE_BOOST_BYTESWAP) + + return boost::endian::endian_reverse(static_cast(x)); + +#elif defined(HAVE_GCC_BYTESWAP) + + return __builtin_bswap16(x); #elif defined(HAVE_MSC_BYTESWAP) - return _byteswap_ushort(x); + return _byteswap_ushort(x); #elif defined(HAVE_GLIBC_BYTESWAP) - return __bswap_16(x); + return __bswap_16(x); #elif defined(HAVE_MAC_BYTESWAP) - return OSSwapInt16(x); + return OSSwapInt16(x); #elif defined(HAVE_OPENBSD_BYTESWAP) - return swap16(x); + return swap16(x); #else - return ((x >> 8) & 0xff) | ((x & 0xff) << 8); + return ((x >> 8) & 0xff) | ((x & 0xff) << 8); #endif - } + } - /*! - * Reverses the order of bytes in an 32-bit integer. - */ - inline uint byteSwap(uint x) - { -#if defined(HAVE_GCC_BYTESWAP) + /*! + * Reverses the order of bytes in an 32-bit integer. + */ + inline unsigned int byteSwap(unsigned int x) + { +#if defined(HAVE_BOOST_BYTESWAP) - return __builtin_bswap32(x); + return boost::endian::endian_reverse(static_cast(x)); + +#elif defined(HAVE_GCC_BYTESWAP) + + return __builtin_bswap32(x); #elif defined(HAVE_MSC_BYTESWAP) - return _byteswap_ulong(x); + return _byteswap_ulong(x); #elif defined(HAVE_GLIBC_BYTESWAP) - return __bswap_32(x); + return __bswap_32(x); #elif defined(HAVE_MAC_BYTESWAP) - return OSSwapInt32(x); + return OSSwapInt32(x); #elif defined(HAVE_OPENBSD_BYTESWAP) - return swap32(x); + return swap32(x); #else - return ((x & 0xff000000u) >> 24) - | ((x & 0x00ff0000u) >> 8) - | ((x & 0x0000ff00u) << 8) - | ((x & 0x000000ffu) << 24); + return ((x & 0xff000000u) >> 24) + | ((x & 0x00ff0000u) >> 8) + | ((x & 0x0000ff00u) << 8) + | ((x & 0x000000ffu) << 24); #endif - } + } - /*! - * Reverses the order of bytes in an 64-bit integer. - */ - inline ulonglong byteSwap(ulonglong x) - { -#if defined(HAVE_GCC_BYTESWAP) + /*! + * Reverses the order of bytes in an 64-bit integer. + */ + inline unsigned long long byteSwap(unsigned long long x) + { +#if defined(HAVE_BOOST_BYTESWAP) + + return boost::endian::endian_reverse(static_cast(x)); - return __builtin_bswap64(x); +#elif defined(HAVE_GCC_BYTESWAP) + + return __builtin_bswap64(x); #elif defined(HAVE_MSC_BYTESWAP) - return _byteswap_uint64(x); + return _byteswap_uint64(x); #elif defined(HAVE_GLIBC_BYTESWAP) - return __bswap_64(x); + return __bswap_64(x); #elif defined(HAVE_MAC_BYTESWAP) - return OSSwapInt64(x); + return OSSwapInt64(x); #elif defined(HAVE_OPENBSD_BYTESWAP) - return swap64(x); + return swap64(x); #else - return ((x & 0xff00000000000000ull) >> 56) - | ((x & 0x00ff000000000000ull) >> 40) - | ((x & 0x0000ff0000000000ull) >> 24) - | ((x & 0x000000ff00000000ull) >> 8) - | ((x & 0x00000000ff000000ull) << 8) - | ((x & 0x0000000000ff0000ull) << 24) - | ((x & 0x000000000000ff00ull) << 40) - | ((x & 0x00000000000000ffull) << 56); + return ((x & 0xff00000000000000ull) >> 56) + | ((x & 0x00ff000000000000ull) >> 40) + | ((x & 0x0000ff0000000000ull) >> 24) + | ((x & 0x000000ff00000000ull) >> 8) + | ((x & 0x00000000ff000000ull) << 8) + | ((x & 0x0000000000ff0000ull) << 24) + | ((x & 0x000000000000ff00ull) << 40) + | ((x & 0x00000000000000ffull) << 56); #endif - } + } - /*! - * Returns a formatted string just like standard sprintf(), but makes use of - * safer functions such as snprintf() if available. - */ - inline String formatString(const char *format, ...) - { - // Sufficient buffer size for the current internal uses. - // Consider changing this value when you use this function. + /*! + * Returns a formatted string just like standard sprintf(), but makes use of + * safer functions such as snprintf() if available. + */ + inline String formatString(const char *format, ...) + { + // Sufficient buffer size for the current internal uses. + // Consider changing this value when you use this function. - static const size_t BufferSize = 128; + static const size_t BufferSize = 128; - va_list args; - va_start(args, format); + va_list args; + va_start(args, format); - char buf[BufferSize]; - int length; + char buf[BufferSize]; + int length; #if defined(HAVE_VSNPRINTF) - length = vsnprintf(buf, BufferSize, format, args); + length = vsnprintf(buf, BufferSize, format, args); #elif defined(HAVE_VSPRINTF_S) - length = vsprintf_s(buf, format, args); + length = vsprintf_s(buf, format, args); #else - // The last resort. May cause a buffer overflow. + // The last resort. May cause a buffer overflow. - length = vsprintf(buf, format, args); - if(length >= BufferSize) { - debug("Utils::formatString() - Buffer overflow! Returning an empty string."); - length = -1; - } + length = vsprintf(buf, format, args); + if(length >= BufferSize) { + debug("Utils::formatString() - Buffer overflow! Returning an empty string."); + length = -1; + } #endif - va_end(args); + va_end(args); - if(length != -1) - return String(buf); - else - return String::null; - } + if(length > 0) + return String(buf); + else + return String(); + } - /*! - * The types of byte order of the running system. - */ - enum ByteOrder - { - //! Little endian systems. - LittleEndian, - //! Big endian systems. - BigEndian - }; - - /*! - * Returns the integer byte order of the system. - */ - inline ByteOrder systemByteOrder() - { - union { - int i; - char c; - } u; - - u.i = 1; - if(u.c == 1) - return LittleEndian; - else - return BigEndian; - } + /*! + * Returns whether the two strings s1 and s2 are equal, ignoring the case of + * the characters. + * + * We took the trouble to define this one here, since there are some + * incompatible variations of case insensitive strcmp(). + */ + inline bool equalsIgnoreCase(const char *s1, const char *s2) + { + while(*s1 != '\0' && *s2 != '\0' && ::tolower(*s1) == ::tolower(*s2)) { + s1++; + s2++; + } - /*! - * Returns the IEEE754 byte order of the system. - */ - inline ByteOrder floatByteOrder() - { - union { - double d; - char c; - } u; - - // 1.0 is stored in memory like 0x3FF0000000000000 in canonical form. - // So the first byte is zero if little endian. - - u.d = 1.0; - if(u.c == 0) - return LittleEndian; - else - return BigEndian; - } + return (*s1 == '\0' && *s2 == '\0'); + } + /*! + * The types of byte order of the running system. + */ + enum ByteOrder + { + //! Little endian systems. + LittleEndian, + //! Big endian systems. + BigEndian + }; + + /*! + * Returns the integer byte order of the system. + */ + inline ByteOrder systemByteOrder() + { + union { + int i; + char c; + } u; + + u.i = 1; + if(u.c == 1) + return LittleEndian; + else + return BigEndian; + } + + /*! + * Returns the IEEE754 byte order of the system. + */ + inline ByteOrder floatByteOrder() + { + union { + double d; + char c; + } u; + + // 1.0 is stored in memory like 0x3FF0000000000000 in canonical form. + // So the first byte is zero if little endian. + + u.d = 1.0; + if(u.c == 0) + return LittleEndian; + else + return BigEndian; + } + } } } diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tzlib.cpp clementine-1.3.1-218/3rdparty/taglib/toolkit/tzlib.cpp --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tzlib.cpp 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tzlib.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,142 @@ +/*************************************************************************** + copyright : (C) 2016 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(HAVE_ZLIB) +# include +#elif defined(HAVE_BOOST_ZLIB) +# include +# include +#endif + +#include +#include + +#include "tzlib.h" + +using namespace TagLib; + +bool zlib::isAvailable() +{ +#if defined(HAVE_ZLIB) || defined(HAVE_BOOST_ZLIB) + + return true; + +#else + + return false; + +#endif +} + +ByteVector zlib::decompress(const ByteVector &data) +{ +#if defined(HAVE_ZLIB) + + z_stream stream = {}; + + if(inflateInit(&stream) != Z_OK) { + debug("zlib::decompress() - Failed to initizlize zlib."); + return ByteVector(); + } + + ByteVector inData = data; + + stream.avail_in = static_cast(inData.size()); + stream.next_in = reinterpret_cast(inData.data()); + + const unsigned int chunkSize = 1024; + + ByteVector outData; + + do { + const size_t offset = outData.size(); + outData.resize(outData.size() + chunkSize); + + stream.avail_out = static_cast(chunkSize); + stream.next_out = reinterpret_cast(outData.data() + offset); + + const int result = inflate(&stream, Z_NO_FLUSH); + + if(result == Z_STREAM_ERROR || + result == Z_NEED_DICT || + result == Z_DATA_ERROR || + result == Z_MEM_ERROR) + { + if(result != Z_STREAM_ERROR) + inflateEnd(&stream); + + debug("zlib::decompress() - Error reading compressed stream."); + return ByteVector(); + } + + outData.resize(outData.size() - stream.avail_out); + } while(stream.avail_out == 0); + + inflateEnd(&stream); + + return outData; + +#elif defined(HAVE_BOOST_ZLIB) + + using namespace boost::iostreams; + + struct : public sink + { + ByteVector data; + + typedef char char_type; + typedef sink_tag category; + + std::streamsize write(char const* s, std::streamsize n) + { + const unsigned int originalSize = data.size(); + + data.resize(static_cast(originalSize + n)); + ::memcpy(data.data() + originalSize, s, static_cast(n)); + + return n; + } + } sink; + + try { + zlib_decompressor().write(sink, data.data(), data.size()); + } + catch(const zlib_error &) { + debug("zlib::decompress() - Error reading compressed stream."); + return ByteVector(); + } + + return sink.data; + +#else + + return ByteVector(); + +#endif +} diff -Nru clementine-1.3.1-217/3rdparty/taglib/toolkit/tzlib.h clementine-1.3.1-218/3rdparty/taglib/toolkit/tzlib.h --- clementine-1.3.1-217/3rdparty/taglib/toolkit/tzlib.h 1970-01-01 00:00:00.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/toolkit/tzlib.h 2016-07-19 15:25:23.000000000 +0000 @@ -0,0 +1,54 @@ +/*************************************************************************** + copyright : (C) 2016 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_TZLIB_H +#define TAGLIB_TZLIB_H + +#include + +// THIS FILE IS NOT A PART OF THE TAGLIB API + +#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header + +namespace TagLib { + + namespace zlib { + + /*! + * Returns whether or not zlib is installed and ready to use. + */ + bool isAvailable(); + + /*! + * Decompress \a data by zlib. + */ + ByteVector decompress(const ByteVector &data); + + } +} + +#endif + +#endif diff -Nru clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudiofile.cpp clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudiofile.cpp --- clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudiofile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudiofile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -33,6 +33,7 @@ #include #include #include +#include #include "trueaudiofile.h" #include "id3v1tag.h" @@ -54,9 +55,7 @@ ID3v2Location(-1), ID3v2OriginalSize(0), ID3v1Location(-1), - properties(0), - hasID3v1(false), - hasID3v2(false) {} + properties(0) {} ~FilePrivate() { @@ -65,19 +64,13 @@ const ID3v2::FrameFactory *ID3v2FrameFactory; long ID3v2Location; - uint ID3v2OriginalSize; + long ID3v2OriginalSize; long ID3v1Location; TagUnion tag; Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasID3v1; - bool hasID3v2; }; //////////////////////////////////////////////////////////////////////////////// @@ -130,26 +123,20 @@ PropertyMap TrueAudio::File::properties() const { - // once Tag::properties() is virtual, this case distinction could actually be done - // within TagUnion. - if(d->hasID3v2) - return d->tag.access(TrueAudioID3v2Index, false)->properties(); - if(d->hasID3v1) - return d->tag.access(TrueAudioID3v1Index, false)->properties(); - return PropertyMap(); + return d->tag.properties(); } void TrueAudio::File::removeUnsupportedProperties(const StringList &unsupported) { - if(d->hasID3v2) - d->tag.access(TrueAudioID3v2Index, false)->removeUnsupportedProperties(unsupported); + d->tag.removeUnsupportedProperties(unsupported); } PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties) { - if(d->hasID3v1) - d->tag.access(TrueAudioID3v1Index, false)->setProperties(properties); - return d->tag.access(TrueAudioID3v2Index, true)->setProperties(properties); + if(ID3v1Tag()) + ID3v1Tag()->setProperties(properties); + + return ID3v2Tag(true)->setProperties(properties); } TrueAudio::Properties *TrueAudio::File::audioProperties() const @@ -172,40 +159,59 @@ // Update ID3v2 tag if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { - if(!d->hasID3v2) { + + // ID3v2 tag is not empty. Update the old one or create a new one. + + if(d->ID3v2Location < 0) d->ID3v2Location = 0; - d->ID3v2OriginalSize = 0; - } - ByteVector data = ID3v2Tag()->render(); + + const ByteVector data = ID3v2Tag()->render(); insert(data, d->ID3v2Location, d->ID3v2OriginalSize); - d->ID3v1Location -= d->ID3v2OriginalSize - data.size(); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->ID3v2OriginalSize); + d->ID3v2OriginalSize = data.size(); - d->hasID3v2 = true; } - else if(d->hasID3v2) { - removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); - d->ID3v1Location -= d->ID3v2OriginalSize; - d->ID3v2Location = -1; - d->ID3v2OriginalSize = 0; - d->hasID3v2 = false; + else { + + // ID3v2 tag is empty. Remove the old one. + + if(d->ID3v2Location >= 0) { + removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->ID3v2OriginalSize; + + d->ID3v2Location = -1; + d->ID3v2OriginalSize = 0; + } } // Update ID3v1 tag if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { - if(!d->hasID3v1) { + + // ID3v1 tag is not empty. Update the old one or create a new one. + + if(d->ID3v1Location >= 0) { + seek(d->ID3v1Location); + } + else { seek(0, End); d->ID3v1Location = tell(); } - else - seek(d->ID3v1Location); + writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; } - else if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->ID3v1Location = -1; - d->hasID3v1 = false; + else { + + // ID3v1 tag is empty. Remove the old one. + + if(d->ID3v1Location >= 0) { + truncate(d->ID3v1Location); + d->ID3v1Location = -1; + } } return true; @@ -223,27 +229,24 @@ void TrueAudio::File::strip(int tags) { - if(tags & ID3v1) { + if(tags & ID3v1) d->tag.set(TrueAudioID3v1Index, 0); - ID3v2Tag(true); - } - if(tags & ID3v2) { + if(tags & ID3v2) d->tag.set(TrueAudioID3v2Index, 0); - if(!ID3v1Tag()) - ID3v2Tag(true); - } + if(!ID3v1Tag()) + ID3v2Tag(true); } bool TrueAudio::File::hasID3v1Tag() const { - return d->hasID3v1; + return (d->ID3v1Location >= 0); } bool TrueAudio::File::hasID3v2Tag() const { - return d->hasID3v2; + return (d->ID3v2Location >= 0); } //////////////////////////////////////////////////////////////////////////////// @@ -254,30 +257,21 @@ { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { - d->tag.set(TrueAudioID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); - d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); - - if(ID3v2Tag()->header()->tagSize() <= 0) - d->tag.set(TrueAudioID3v2Index, 0); - else - d->hasID3v2 = true; } // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); - if(d->ID3v1Location >= 0) { + if(d->ID3v1Location >= 0) d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - if(!d->hasID3v1) + if(d->ID3v1Location < 0) ID3v2Tag(true); // Look for TrueAudio metadata @@ -286,12 +280,12 @@ long streamLength; - if(d->hasID3v1) + if(d->ID3v1Location >= 0) streamLength = d->ID3v1Location; else streamLength = length(); - if(d->hasID3v2) { + if(d->ID3v2Location >= 0) { seek(d->ID3v2Location + d->ID3v2OriginalSize); streamLength -= (d->ID3v2Location + d->ID3v2OriginalSize); } @@ -302,30 +296,3 @@ d->properties = new Properties(readBlock(TrueAudio::HeaderSize), streamLength); } } - -long TrueAudio::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long TrueAudio::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff -Nru clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudiofile.h clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudiofile.h --- clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudiofile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudiofile.h 2016-07-19 15:25:23.000000000 +0000 @@ -240,8 +240,6 @@ File &operator=(const File &); void read(bool readProperties); - long findID3v1(); - long findID3v2(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudioproperties.cpp clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudioproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudioproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudioproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -54,7 +54,7 @@ int sampleRate; int channels; int bitsPerSample; - uint sampleFrames; + unsigned int sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// @@ -108,7 +108,7 @@ return d->channels; } -TagLib::uint TrueAudio::Properties::sampleFrames() const +unsigned int TrueAudio::Properties::sampleFrames() const { return d->sampleFrames; } @@ -134,7 +134,7 @@ return; } - uint pos = 3; + unsigned int pos = 3; d->version = data[pos] - '0'; pos += 1; diff -Nru clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudioproperties.h clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudioproperties.h --- clementine-1.3.1-217/3rdparty/taglib/trueaudio/trueaudioproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/trueaudio/trueaudioproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -38,7 +38,7 @@ class File; - static const uint HeaderSize = 18; + static const unsigned int HeaderSize = 18; //! An implementation of audio property reading for TrueAudio @@ -111,7 +111,7 @@ /*! * Returns the total number of sample frames */ - uint sampleFrames() const; + unsigned int sampleFrames() const; /*! * Returns the major version number. diff -Nru clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackfile.cpp clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -32,6 +32,7 @@ #include #include #include +#include #include "wavpackfile.h" #include "id3v1tag.h" @@ -53,9 +54,7 @@ APELocation(-1), APESize(0), ID3v1Location(-1), - properties(0), - hasAPE(false), - hasID3v1(false) {} + properties(0) {} ~FilePrivate() { @@ -63,19 +62,13 @@ } long APELocation; - uint APESize; + long APESize; long ID3v1Location; TagUnion tag; Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasAPE; - bool hasID3v1; }; //////////////////////////////////////////////////////////////////////////////// @@ -110,26 +103,20 @@ PropertyMap WavPack::File::properties() const { - if(d->hasAPE) - return d->tag.access(WavAPEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access(WavID3v1Index, false)->properties(); - return PropertyMap(); + return d->tag.properties(); } - void WavPack::File::removeUnsupportedProperties(const StringList &unsupported) { - if(d->hasAPE) - d->tag.access(WavAPEIndex, false)->removeUnsupportedProperties(unsupported); + d->tag.removeUnsupportedProperties(unsupported); } - PropertyMap WavPack::File::setProperties(const PropertyMap &properties) { - if(d->hasID3v1) - d->tag.access(WavID3v1Index, false)->setProperties(properties); - return d->tag.access(WavAPEIndex, true)->setProperties(properties); + if(ID3v1Tag()) + ID3v1Tag()->setProperties(properties); + + return APETag(true)->setProperties(properties); } WavPack::Properties *WavPack::File::audioProperties() const @@ -146,64 +133,67 @@ // Update ID3v1 tag - if(ID3v1Tag()) { - if(d->hasID3v1) { + if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { + + // ID3v1 tag is not empty. Update the old one or create a new one. + + if(d->ID3v1Location >= 0) { seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); } else { seek(0, End); d->ID3v1Location = tell(); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; } + + writeBlock(ID3v1Tag()->render()); } else { - if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->hasID3v1 = false; - if(d->hasAPE) { - if(d->APELocation > d->ID3v1Location) - d->APELocation -= 128; - } + + // ID3v1 tag is empty. Remove the old one. + + if(d->ID3v1Location >= 0) { + truncate(d->ID3v1Location); + d->ID3v1Location = -1; } } // Update APE tag - if(APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APESize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; + if(APETag() && !APETag()->isEmpty()) { + + // APE tag is not empty. Update the old one or create a new one. + + if(d->APELocation < 0) { + if(d->ID3v1Location >= 0) d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APESize; - } - else { - seek(0, End); - d->APELocation = tell(); - writeBlock(APETag()->render()); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } + else + d->APELocation = length(); } + + const ByteVector data = APETag()->render(); + insert(data, d->APELocation, d->APESize); + + if(d->ID3v1Location >= 0) + d->ID3v1Location += (static_cast(data.size()) - d->APESize); + + d->APESize = data.size(); } else { - if(d->hasAPE) { + + // APE tag is empty. Remove the old one. + + if(d->APELocation >= 0) { removeBlock(d->APELocation, d->APESize); - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) { - d->ID3v1Location -= d->APESize; - } - } + + if(d->ID3v1Location >= 0) + d->ID3v1Location -= d->APESize; + + d->APELocation = -1; + d->APESize = 0; } } - return true; + return true; } ID3v1::Tag *WavPack::File::ID3v1Tag(bool create) @@ -218,27 +208,24 @@ void WavPack::File::strip(int tags) { - if(tags & ID3v1) { + if(tags & ID3v1) d->tag.set(WavID3v1Index, 0); - APETag(true); - } - if(tags & APE) { + if(tags & APE) d->tag.set(WavAPEIndex, 0); - if(!ID3v1Tag()) - APETag(true); - } + if(!ID3v1Tag()) + APETag(true); } bool WavPack::File::hasID3v1Tag() const { - return d->hasID3v1; + return (d->ID3v1Location >= 0); } bool WavPack::File::hasAPETag() const { - return d->hasAPE; + return (d->APELocation >= 0); } //////////////////////////////////////////////////////////////////////////////// @@ -249,25 +236,22 @@ { // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); - if(d->ID3v1Location >= 0) { + if(d->ID3v1Location >= 0) d->tag.set(WavID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } // Look for an APE tag - d->APELocation = findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { d->tag.set(WavAPEIndex, new APE::Tag(this, d->APELocation)); d->APESize = APETag()->footer()->completeTagSize(); - d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; - d->hasAPE = true; + d->APELocation = d->APELocation + APE::Footer::size() - d->APESize; } - if(!d->hasID3v1) + if(d->ID3v1Location >= 0) APETag(true); // Look for WavPack audio properties @@ -276,9 +260,9 @@ long streamLength; - if(d->hasAPE) + if(d->APELocation >= 0) streamLength = d->APELocation; - else if(d->hasID3v1) + else if(d->ID3v1Location >= 0) streamLength = d->ID3v1Location; else streamLength = length(); @@ -286,35 +270,3 @@ d->properties = new Properties(this, streamLength); } } - -long WavPack::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -long WavPack::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} diff -Nru clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackfile.h clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackfile.h --- clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -135,9 +135,6 @@ * Saves the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. At worst it will corrupt the file. */ virtual bool save(); @@ -208,8 +205,6 @@ File &operator=(const File &); void read(bool readProperties); - long findID3v1(); - long findAPE(); class FilePrivate; FilePrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackproperties.cpp clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -58,7 +58,7 @@ int version; int bitsPerSample; bool lossless; - uint sampleFrames; + unsigned int sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// @@ -129,7 +129,7 @@ return d->lossless; } -TagLib::uint WavPack::Properties::sampleFrames() const +unsigned int WavPack::Properties::sampleFrames() const { return d->sampleFrames; } @@ -155,8 +155,8 @@ #define SRATE_LSB 23 #define SRATE_MASK (0xfL << SRATE_LSB) -#define MIN_STREAM_VERS 0x402 -#define MAX_STREAM_VERS 0x410 +#define MIN_STREAM_VERS 0x402 +#define MAX_STREAM_VERS 0x410 #define FINAL_BLOCK 0x1000 @@ -178,7 +178,7 @@ break; } - const uint flags = data.toUInt(24, false); + const unsigned int flags = data.toUInt(24, false); if(offset == 0) { d->version = data.toShort(8, false); @@ -196,7 +196,7 @@ if(flags & FINAL_BLOCK) break; - const uint blockSize = data.toUInt(4, false); + const unsigned int blockSize = data.toUInt(4, false); offset += blockSize + 8; } @@ -210,7 +210,7 @@ } } -TagLib::uint WavPack::Properties::seekFinalIndex(File *file, long streamLength) +unsigned int WavPack::Properties::seekFinalIndex(File *file, long streamLength) { const long offset = file->rfind("wvpk", streamLength); if(offset == -1) @@ -225,12 +225,12 @@ if(version < MIN_STREAM_VERS || version > MAX_STREAM_VERS) return 0; - const uint flags = data.toUInt(24, false); + const unsigned int flags = data.toUInt(24, false); if(!(flags & FINAL_BLOCK)) return 0; - const uint blockIndex = data.toUInt(16, false); - const uint blockSamples = data.toUInt(20, false); + const unsigned int blockIndex = data.toUInt(16, false); + const unsigned int blockSamples = data.toUInt(20, false); return blockIndex + blockSamples; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackproperties.h clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackproperties.h --- clementine-1.3.1-217/3rdparty/taglib/wavpack/wavpackproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/wavpack/wavpackproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -39,7 +39,7 @@ class File; - static const uint HeaderSize = 32; + static const unsigned int HeaderSize = 32; //! An implementation of audio property reading for WavPack @@ -126,7 +126,7 @@ /*! * Returns the total number of audio samples in file. */ - uint sampleFrames() const; + unsigned int sampleFrames() const; /*! * Returns WavPack version. @@ -138,7 +138,7 @@ Properties &operator=(const Properties &); void read(File *file, long streamLength); - uint seekFinalIndex(File *file, long streamLength); + unsigned int seekFinalIndex(File *file, long streamLength); class PropertiesPrivate; PropertiesPrivate *d; diff -Nru clementine-1.3.1-217/3rdparty/taglib/xm/xmfile.cpp clementine-1.3.1-218/3rdparty/taglib/xm/xmfile.cpp --- clementine-1.3.1-217/3rdparty/taglib/xm/xmfile.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/xm/xmfile.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tstringlist.h" @@ -30,9 +34,6 @@ using namespace TagLib; using namespace XM; -using TagLib::uint; -using TagLib::ushort; -using TagLib::ulong; /*! * The Reader classes are helpers to make handling of the stripped XM @@ -74,35 +75,35 @@ * Reads associated values from \a file, but never reads more * then \a limit bytes. */ - virtual uint read(TagLib::File &file, uint limit) = 0; + virtual unsigned int read(TagLib::File &file, unsigned int limit) = 0; /*! * Returns the number of bytes this reader would like to read. */ - virtual uint size() const = 0; + virtual unsigned int size() const = 0; }; class SkipReader : public Reader { public: - SkipReader(uint size) : m_size(size) + SkipReader(unsigned int size) : m_size(size) { } - uint read(TagLib::File &file, uint limit) + unsigned int read(TagLib::File &file, unsigned int limit) { - uint count = std::min(m_size, limit); + unsigned int count = std::min(m_size, limit); file.seek(count, TagLib::File::Current); return count; } - uint size() const + unsigned int size() const { return m_size; } private: - uint m_size; + unsigned int m_size; }; template @@ -120,39 +121,39 @@ class StringReader : public ValueReader { public: - StringReader(String &string, uint size) : + StringReader(String &string, unsigned int size) : ValueReader(string), m_size(size) { } - uint read(TagLib::File &file, uint limit) + unsigned int read(TagLib::File &file, unsigned int limit) { ByteVector data = file.readBlock(std::min(m_size, limit)); - uint count = data.size(); + unsigned int count = data.size(); int index = data.find((char) 0); if(index > -1) { data.resize(index); } - data.replace((char) 0xff, ' '); + data.replace('\xff', ' '); value = data; return count; } - uint size() const + unsigned int size() const { return m_size; } private: - uint m_size; + unsigned int m_size; }; -class ByteReader : public ValueReader +class ByteReader : public ValueReader { public: - ByteReader(uchar &byte) : ValueReader(byte) {} + ByteReader(unsigned char &byte) : ValueReader(byte) {} - uint read(TagLib::File &file, uint limit) + unsigned int read(TagLib::File &file, unsigned int limit) { ByteVector data = file.readBlock(std::min(1U,limit)); if(data.size() > 0) { @@ -161,7 +162,7 @@ return data.size(); } - uint size() const + unsigned int size() const { return 1; } @@ -180,41 +181,41 @@ bool bigEndian; }; -class U16Reader : public NumberReader +class U16Reader : public NumberReader { public: - U16Reader(ushort &value, bool bigEndian) - : NumberReader(value, bigEndian) {} + U16Reader(unsigned short &value, bool bigEndian) + : NumberReader(value, bigEndian) {} - uint read(TagLib::File &file, uint limit) + unsigned int read(TagLib::File &file, unsigned int limit) { ByteVector data = file.readBlock(std::min(2U,limit)); value = data.toUShort(bigEndian); return data.size(); } - uint size() const + unsigned int size() const { return 2; } }; -class U32Reader : public NumberReader +class U32Reader : public NumberReader { public: - U32Reader(ulong &value, bool bigEndian = true) : - NumberReader(value, bigEndian) + U32Reader(unsigned long &value, bool bigEndian = true) : + NumberReader(value, bigEndian) { } - uint read(TagLib::File &file, uint limit) + unsigned int read(TagLib::File &file, unsigned int limit) { ByteVector data = file.readBlock(std::min(4U,limit)); value = data.toUInt(bigEndian); return data.size(); } - uint size() const + unsigned int size() const { return 4; } @@ -240,7 +241,7 @@ /*! * Don't read anything but skip \a size bytes. */ - StructReader &skip(uint size) + StructReader &skip(unsigned int size) { m_readers.append(new SkipReader(size)); return *this; @@ -249,7 +250,7 @@ /*! * Read a string of \a size characters (bytes) into \a string. */ - StructReader &string(String &string, uint size) + StructReader &string(String &string, unsigned int size) { m_readers.append(new StringReader(string, size)); return *this; @@ -258,7 +259,7 @@ /*! * Read a byte into \a byte. */ - StructReader &byte(uchar &byte) + StructReader &byte(unsigned char &byte) { m_readers.append(new ByteReader(byte)); return *this; @@ -268,7 +269,7 @@ * Read a unsigned 16 Bit integer into \a number. The byte order * is controlled by \a bigEndian. */ - StructReader &u16(ushort &number, bool bigEndian) + StructReader &u16(unsigned short &number, bool bigEndian) { m_readers.append(new U16Reader(number, bigEndian)); return *this; @@ -277,7 +278,7 @@ /*! * Read a unsigned 16 Bit little endian integer into \a number. */ - StructReader &u16L(ushort &number) + StructReader &u16L(unsigned short &number) { return u16(number, false); } @@ -285,7 +286,7 @@ /*! * Read a unsigned 16 Bit big endian integer into \a number. */ - StructReader &u16B(ushort &number) + StructReader &u16B(unsigned short &number) { return u16(number, true); } @@ -294,7 +295,7 @@ * Read a unsigned 32 Bit integer into \a number. The byte order * is controlled by \a bigEndian. */ - StructReader &u32(ulong &number, bool bigEndian) + StructReader &u32(unsigned long &number, bool bigEndian) { m_readers.append(new U32Reader(number, bigEndian)); return *this; @@ -303,7 +304,7 @@ /*! * Read a unsigned 32 Bit little endian integer into \a number. */ - StructReader &u32L(ulong &number) + StructReader &u32L(unsigned long &number) { return u32(number, false); } @@ -311,14 +312,14 @@ /*! * Read a unsigned 32 Bit big endian integer into \a number. */ - StructReader &u32B(ulong &number) + StructReader &u32B(unsigned long &number) { return u32(number, true); } - uint size() const + unsigned int size() const { - uint size = 0; + unsigned int size = 0; for(List::ConstIterator i = m_readers.begin(); i != m_readers.end(); ++ i) { size += (*i)->size(); @@ -326,12 +327,12 @@ return size; } - uint read(TagLib::File &file, uint limit) + unsigned int read(TagLib::File &file, unsigned int limit) { - uint sumcount = 0; + unsigned int sumcount = 0; for(List::ConstIterator i = m_readers.begin(); limit > 0 && i != m_readers.end(); ++ i) { - uint count = (*i)->read(file, limit); + unsigned int count = (*i)->read(file, limit); limit -= count; sumcount += count; } @@ -411,27 +412,27 @@ writeString(d->tag.trackerName(), 20); seek(60); - ulong headerSize = 0; + unsigned long headerSize = 0; if(!readU32L(headerSize)) return false; seek(70); - ushort patternCount = 0; - ushort instrumentCount = 0; + unsigned short patternCount = 0; + unsigned short instrumentCount = 0; if(!readU16L(patternCount) || !readU16L(instrumentCount)) return false; - long pos = 60 + headerSize; // should be offset_t in taglib2. + long pos = 60 + headerSize; // should be long long in taglib2. // need to read patterns again in order to seek to the instruments: - for(ushort i = 0; i < patternCount; ++ i) { + for(unsigned short i = 0; i < patternCount; ++ i) { seek(pos); - ulong patternHeaderLength = 0; + unsigned long patternHeaderLength = 0; if(!readU32L(patternHeaderLength) || patternHeaderLength < 4) return false; seek(pos + 7); - ushort dataSize = 0; + unsigned short dataSize = 0; if (!readU16L(dataSize)) return false; @@ -439,28 +440,28 @@ } const StringList lines = d->tag.comment().split("\n"); - uint sampleNameIndex = instrumentCount; - for(ushort i = 0; i < instrumentCount; ++ i) { + unsigned int sampleNameIndex = instrumentCount; + for(unsigned short i = 0; i < instrumentCount; ++ i) { seek(pos); - ulong instrumentHeaderSize = 0; + unsigned long instrumentHeaderSize = 0; if(!readU32L(instrumentHeaderSize) || instrumentHeaderSize < 4) return false; seek(pos + 4); - const uint len = std::min(22UL, instrumentHeaderSize - 4U); + const unsigned int len = std::min(22UL, instrumentHeaderSize - 4U); if(i >= lines.size()) - writeString(String::null, len); + writeString(String(), len); else writeString(lines[i], len); - ushort sampleCount = 0; + unsigned short sampleCount = 0; if(instrumentHeaderSize >= 29U) { seek(pos + 27); if(!readU16L(sampleCount)) return false; } - ulong sampleHeaderSize = 0; + unsigned long sampleHeaderSize = 0; if(sampleCount > 0) { seek(pos + 29); if(instrumentHeaderSize < 33U || !readU32L(sampleHeaderSize)) @@ -469,18 +470,18 @@ pos += instrumentHeaderSize; - for(ushort j = 0; j < sampleCount; ++ j) { + for(unsigned short j = 0; j < sampleCount; ++ j) { if(sampleHeaderSize > 4U) { seek(pos); - ulong sampleLength = 0; + unsigned long sampleLength = 0; if(!readU32L(sampleLength)) return false; if(sampleHeaderSize > 18U) { seek(pos + 18); - const uint len = std::min(sampleHeaderSize - 18U, 22UL); + const unsigned int len = std::min(sampleHeaderSize - 18U, 22UL); if(sampleNameIndex >= lines.size()) - writeString(String::null, len); + writeString(String(), len); else writeString(lines[sampleNameIndex ++], len); } @@ -513,14 +514,14 @@ READ_U32L_AS(headerSize); READ_ASSERT(headerSize >= 4); - ushort length = 0; - ushort restartPosition = 0; - ushort channels = 0; - ushort patternCount = 0; - ushort instrumentCount = 0; - ushort flags = 0; - ushort tempo = 0; - ushort bpmSpeed = 0; + unsigned short length = 0; + unsigned short restartPosition = 0; + unsigned short channels = 0; + unsigned short patternCount = 0; + unsigned short instrumentCount = 0; + unsigned short flags = 0; + unsigned short tempo = 0; + unsigned short bpmSpeed = 0; StructReader header; header.u16L(length) @@ -532,8 +533,8 @@ .u16L(tempo) .u16L(bpmSpeed); - uint count = header.read(*this, headerSize - 4U); - uint size = std::min(headerSize - 4U, (ulong)header.size()); + unsigned int count = header.read(*this, headerSize - 4U); + unsigned int size = std::min(headerSize - 4U, (unsigned long)header.size()); READ_ASSERT(count == size); @@ -549,43 +550,43 @@ seek(60 + headerSize); // read patterns: - for(ushort i = 0; i < patternCount; ++ i) { + for(unsigned short i = 0; i < patternCount; ++ i) { READ_U32L_AS(patternHeaderLength); READ_ASSERT(patternHeaderLength >= 4); - uchar packingType = 0; - ushort rowCount = 0; - ushort dataSize = 0; + unsigned char packingType = 0; + unsigned short rowCount = 0; + unsigned short dataSize = 0; StructReader pattern; pattern.byte(packingType).u16L(rowCount).u16L(dataSize); - uint count = pattern.read(*this, patternHeaderLength - 4U); - READ_ASSERT(count == std::min(patternHeaderLength - 4U, (ulong)pattern.size())); + unsigned int count = pattern.read(*this, patternHeaderLength - 4U); + READ_ASSERT(count == std::min(patternHeaderLength - 4U, (unsigned long)pattern.size())); seek(patternHeaderLength - (4 + count) + dataSize, Current); } StringList intrumentNames; StringList sampleNames; - uint sumSampleCount = 0; + unsigned int sumSampleCount = 0; // read instruments: - for(ushort i = 0; i < instrumentCount; ++ i) { + for(unsigned short i = 0; i < instrumentCount; ++ i) { READ_U32L_AS(instrumentHeaderSize); READ_ASSERT(instrumentHeaderSize >= 4); String instrumentName; - uchar instrumentType = 0; - ushort sampleCount = 0; + unsigned char instrumentType = 0; + unsigned short sampleCount = 0; StructReader instrument; instrument.string(instrumentName, 22).byte(instrumentType).u16L(sampleCount); // 4 for instrumentHeaderSize - uint count = 4 + instrument.read(*this, instrumentHeaderSize - 4U); - READ_ASSERT(count == std::min(instrumentHeaderSize, (ulong)instrument.size() + 4)); + unsigned int count = 4 + instrument.read(*this, instrumentHeaderSize - 4U); + READ_ASSERT(count == std::min(instrumentHeaderSize, (unsigned long)instrument.size() + 4)); - ulong sampleHeaderSize = 0; + unsigned long sampleHeaderSize = 0; long offset = 0; if(sampleCount > 0) { sumSampleCount += sampleCount; @@ -594,16 +595,16 @@ // skip unhandeled header proportion: seek(instrumentHeaderSize - count - 4, Current); - for(ushort j = 0; j < sampleCount; ++ j) { - ulong sampleLength = 0; - ulong loopStart = 0; - ulong loopLength = 0; - uchar volume = 0; - uchar finetune = 0; - uchar sampleType = 0; - uchar panning = 0; - uchar noteNumber = 0; - uchar compression = 0; + for(unsigned short j = 0; j < sampleCount; ++ j) { + unsigned long sampleLength = 0; + unsigned long loopStart = 0; + unsigned long loopLength = 0; + unsigned char volume = 0; + unsigned char finetune = 0; + unsigned char sampleType = 0; + unsigned char panning = 0; + unsigned char noteNumber = 0; + unsigned char compression = 0; String sampleName; StructReader sample; sample.u32L(sampleLength) @@ -617,8 +618,8 @@ .byte(compression) .string(sampleName, 22); - uint count = sample.read(*this, sampleHeaderSize); - READ_ASSERT(count == std::min(sampleHeaderSize, (ulong)sample.size())); + unsigned int count = sample.read(*this, sampleHeaderSize); + READ_ASSERT(count == std::min(sampleHeaderSize, (unsigned long)sample.size())); // skip unhandeled header proportion: seek(sampleHeaderSize - count, Current); @@ -635,7 +636,7 @@ d->properties.setSampleCount(sumSampleCount); String comment(intrumentNames.toString("\n")); - if(sampleNames.size() > 0) { + if(!sampleNames.isEmpty()) { comment += "\n"; comment += sampleNames.toString("\n"); } diff -Nru clementine-1.3.1-217/3rdparty/taglib/xm/xmfile.h clementine-1.3.1-218/3rdparty/taglib/xm/xmfile.h --- clementine-1.3.1-217/3rdparty/taglib/xm/xmfile.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/xm/xmfile.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_XMFILE_H diff -Nru clementine-1.3.1-217/3rdparty/taglib/xm/xmproperties.cpp clementine-1.3.1-218/3rdparty/taglib/xm/xmproperties.cpp --- clementine-1.3.1-217/3rdparty/taglib/xm/xmproperties.cpp 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/xm/xmproperties.cpp 2016-07-19 15:25:23.000000000 +0000 @@ -1,11 +1,11 @@ /*************************************************************************** - copyright :(C) 2011 by Mathias Panzenböck + copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,10 +15,15 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ + #include "xmproperties.h" using namespace TagLib; @@ -41,16 +46,16 @@ { } - ushort lengthInPatterns; - int channels; - ushort version; - ushort restartPosition; - ushort patternCount; - ushort instrumentCount; - uint sampleCount; - ushort flags; - ushort tempo; - ushort bpmSpeed; + unsigned short lengthInPatterns; + int channels; + unsigned short version; + unsigned short restartPosition; + unsigned short patternCount; + unsigned short instrumentCount; + unsigned int sampleCount; + unsigned short flags; + unsigned short tempo; + unsigned short bpmSpeed; }; XM::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : @@ -94,52 +99,52 @@ return d->channels; } -TagLib::ushort XM::Properties::lengthInPatterns() const +unsigned short XM::Properties::lengthInPatterns() const { return d->lengthInPatterns; } -TagLib::ushort XM::Properties::version() const +unsigned short XM::Properties::version() const { return d->version; } -TagLib::ushort XM::Properties::restartPosition() const +unsigned short XM::Properties::restartPosition() const { return d->restartPosition; } -TagLib::ushort XM::Properties::patternCount() const +unsigned short XM::Properties::patternCount() const { return d->patternCount; } -TagLib::ushort XM::Properties::instrumentCount() const +unsigned short XM::Properties::instrumentCount() const { return d->instrumentCount; } -TagLib::uint XM::Properties::sampleCount() const +unsigned int XM::Properties::sampleCount() const { return d->sampleCount; } -TagLib::ushort XM::Properties::flags() const +unsigned short XM::Properties::flags() const { return d->flags; } -TagLib::ushort XM::Properties::tempo() const +unsigned short XM::Properties::tempo() const { return d->tempo; } -TagLib::ushort XM::Properties::bpmSpeed() const +unsigned short XM::Properties::bpmSpeed() const { return d->bpmSpeed; } -void XM::Properties::setLengthInPatterns(ushort lengthInPatterns) +void XM::Properties::setLengthInPatterns(unsigned short lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } @@ -149,42 +154,42 @@ d->channels = channels; } -void XM::Properties::setVersion(ushort version) +void XM::Properties::setVersion(unsigned short version) { d->version = version; } -void XM::Properties::setRestartPosition(ushort restartPosition) +void XM::Properties::setRestartPosition(unsigned short restartPosition) { d->restartPosition = restartPosition; } -void XM::Properties::setPatternCount(ushort patternCount) +void XM::Properties::setPatternCount(unsigned short patternCount) { d->patternCount = patternCount; } -void XM::Properties::setInstrumentCount(ushort instrumentCount) +void XM::Properties::setInstrumentCount(unsigned short instrumentCount) { d->instrumentCount = instrumentCount; } -void XM::Properties::setSampleCount(uint sampleCount) +void XM::Properties::setSampleCount(unsigned int sampleCount) { d->sampleCount = sampleCount; } -void XM::Properties::setFlags(ushort flags) +void XM::Properties::setFlags(unsigned short flags) { d->flags = flags; } -void XM::Properties::setTempo(ushort tempo) +void XM::Properties::setTempo(unsigned short tempo) { d->tempo = tempo; } -void XM::Properties::setBpmSpeed(ushort bpmSpeed) +void XM::Properties::setBpmSpeed(unsigned short bpmSpeed) { d->bpmSpeed = bpmSpeed; } diff -Nru clementine-1.3.1-217/3rdparty/taglib/xm/xmproperties.h clementine-1.3.1-218/3rdparty/taglib/xm/xmproperties.h --- clementine-1.3.1-217/3rdparty/taglib/xm/xmproperties.h 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/3rdparty/taglib/xm/xmproperties.h 2016-07-19 15:25:23.000000000 +0000 @@ -5,7 +5,7 @@ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * + * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * @@ -15,8 +15,12 @@ * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_XMPROPERTIES_H @@ -46,27 +50,27 @@ int sampleRate() const; int channels() const; - ushort lengthInPatterns() const; - ushort version() const; - ushort restartPosition() const; - ushort patternCount() const; - ushort instrumentCount() const; - uint sampleCount() const; - ushort flags() const; - ushort tempo() const; - ushort bpmSpeed() const; + unsigned short lengthInPatterns() const; + unsigned short version() const; + unsigned short restartPosition() const; + unsigned short patternCount() const; + unsigned short instrumentCount() const; + unsigned int sampleCount() const; + unsigned short flags() const; + unsigned short tempo() const; + unsigned short bpmSpeed() const; void setChannels(int channels); - void setLengthInPatterns(ushort lengthInPatterns); - void setVersion(ushort version); - void setRestartPosition(ushort restartPosition); - void setPatternCount(ushort patternCount); - void setInstrumentCount(ushort instrumentCount); - void setSampleCount(uint sampleCount); - void setFlags(ushort flags); - void setTempo(ushort tempo); - void setBpmSpeed(ushort bpmSpeed); + void setLengthInPatterns(unsigned short lengthInPatterns); + void setVersion(unsigned short version); + void setRestartPosition(unsigned short restartPosition); + void setPatternCount(unsigned short patternCount); + void setInstrumentCount(unsigned short instrumentCount); + void setSampleCount(unsigned int sampleCount); + void setFlags(unsigned short flags); + void setTempo(unsigned short tempo); + void setBpmSpeed(unsigned short bpmSpeed); private: Properties(const Properties&); diff -Nru clementine-1.3.1-217/CMakeLists.txt clementine-1.3.1-218/CMakeLists.txt --- clementine-1.3.1-217/CMakeLists.txt 2016-07-18 10:48:59.000000000 +0000 +++ clementine-1.3.1-218/CMakeLists.txt 2016-07-19 15:25:23.000000000 +0000 @@ -95,7 +95,7 @@ option(USE_BUILTIN_TAGLIB "If the system's version of Taglib is too old, compile our builtin version instead" ON) if (USE_BUILTIN_TAGLIB AND TAGLIB_VERSION VERSION_LESS 1.8) message(STATUS "Using builtin taglib because your system's version is too old") - set(TAGLIB_VERSION 1.10.0) + set(TAGLIB_VERSION 1.11.0) set(TAGLIB_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/taglib/;${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/") set(TAGLIB_LIBRARY_DIRS "") set(TAGLIB_LIBRARIES tag) diff -Nru clementine-1.3.1-217/debian/changelog clementine-1.3.1-218/debian/changelog --- clementine-1.3.1-217/debian/changelog 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/debian/changelog 2016-07-19 15:25:27.000000000 +0000 @@ -1,5 +1,5 @@ -clementine (1.3.1-217-g17beaa7~trusty) trusty; urgency=low +clementine (1.3.1-218-ga4e2eab~trusty) trusty; urgency=low - * Version 1.3.1-217-g17beaa7 + * Version 1.3.1-218-ga4e2eab - -- David Sansome Mon, 18 Jul 2016 10:49:03 +0000 + -- David Sansome Tue, 19 Jul 2016 15:25:27 +0000 diff -Nru clementine-1.3.1-217/debian/rules clementine-1.3.1-218/debian/rules --- clementine-1.3.1-217/debian/rules 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/debian/rules 2016-07-19 15:25:27.000000000 +0000 @@ -13,7 +13,7 @@ cd bin && cmake .. \ -DCMAKE_INSTALL_PREFIX=$(CURDIR)/debian/clementine/usr \ -DBUNDLE_PROJECTM_PRESETS=OFF \ - -DFORCE_GIT_REVISION=1.3.1-217-g17beaa7 + -DFORCE_GIT_REVISION=1.3.1-218-ga4e2eab touch configure-stamp build: build-stamp diff -Nru clementine-1.3.1-217/dist/clementine.spec clementine-1.3.1-218/dist/clementine.spec --- clementine-1.3.1-217/dist/clementine.spec 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/dist/clementine.spec 2016-07-19 15:25:27.000000000 +0000 @@ -1,12 +1,12 @@ Name: clementine Version: 1.3.1 -Release: 2.217.g17beaa7%{?dist} +Release: 2.218.ga4e2eab%{?dist} Summary: A music player and library organiser Group: Applications/Multimedia License: GPLv3 URL: http://www.clementine-player.org/ -Source0: %{name}-1.3.1-217-g17beaa7.tar.xz +Source0: %{name}-1.3.1-218-ga4e2eab.tar.xz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: desktop-file-utils liblastfm-devel taglib-devel gettext @@ -57,7 +57,7 @@ * Queue manager %prep -%setup -q -n %{name}-1.3.1-217-g17beaa7 +%setup -q -n %{name}-1.3.1-218-ga4e2eab %build @@ -92,5 +92,5 @@ %{_datadir}/icons/hicolor/scalable/apps/clementine.svg %changelog -* Mon Jul 18 2016 David Sansome - 1.3.1 -- Version 1.3.1-217-g17beaa7 +* Tue Jul 19 2016 David Sansome - 1.3.1 +- Version 1.3.1-218-ga4e2eab diff -Nru clementine-1.3.1-217/dist/Info.plist clementine-1.3.1-218/dist/Info.plist --- clementine-1.3.1-217/dist/Info.plist 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/dist/Info.plist 2016-07-19 15:25:27.000000000 +0000 @@ -9,7 +9,7 @@ CFBundleExecutable clementine CFBundleGetInfoString - Clementine 1.3.1-217-g17beaa7 + Clementine 1.3.1-218-ga4e2eab CFBundleIconFile clementine CFBundleIdentifier @@ -17,15 +17,15 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - 1.3.1-217-g17beaa7 + 1.3.1-218-ga4e2eab CFBundleName Clementine CFBundlePackageType APPL CFBundleShortVersionString - 1.3.1-217-g17beaa7 + 1.3.1-218-ga4e2eab CFBundleVersion - 4096.1.3.1.2.217 + 4096.1.3.1.2.218 CSResourcesFileMapped LSRequiresCarbon diff -Nru clementine-1.3.1-217/dist/maketarball.sh clementine-1.3.1-218/dist/maketarball.sh --- clementine-1.3.1-217/dist/maketarball.sh 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/dist/maketarball.sh 2016-07-19 15:25:27.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/bash name=clementine -version="1.3.1-217-g17beaa7" +version="1.3.1-218-ga4e2eab" deb_dist="trusty" root=$(cd "${0%/*}/.." && echo $PWD/${0##*/}) root=`dirname "$root"` diff -Nru clementine-1.3.1-217/dist/windows/clementine.nsi clementine-1.3.1-218/dist/windows/clementine.nsi --- clementine-1.3.1-217/dist/windows/clementine.nsi 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/dist/windows/clementine.nsi 2016-07-19 15:25:27.000000000 +0000 @@ -3,8 +3,8 @@ !define PRODUCT_PUBLISHER "Clementine" !define PRODUCT_VERSION_MAJOR 1 !define PRODUCT_VERSION_MINOR 3 -!define PRODUCT_DISPLAY_VERSION "1.3.1-217-g17beaa7" -!define PRODUCT_DISPLAY_VERSION_SHORT "1.3.1-217-g17beaa7" +!define PRODUCT_DISPLAY_VERSION "1.3.1-218-ga4e2eab" +!define PRODUCT_DISPLAY_VERSION_SHORT "1.3.1-218-ga4e2eab" !define PRODUCT_WEB_SITE "http://www.clementine-player.org/" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" @@ -104,7 +104,7 @@ !insertmacro MUI_LANGUAGE "Esperanto" Name "${PRODUCT_NAME}" -OutFile "${PRODUCT_NAME}Setup-1.3.1-217-g17beaa7.exe" +OutFile "${PRODUCT_NAME}Setup-1.3.1-218-ga4e2eab.exe" InstallDir "${PRODUCT_INSTALL_DIR}" ; Get the path where Clementine was installed previously and set it as default path diff -Nru clementine-1.3.1-217/dist/windows/clementine-portable.nsi clementine-1.3.1-218/dist/windows/clementine-portable.nsi --- clementine-1.3.1-217/dist/windows/clementine-portable.nsi 2016-07-18 10:49:03.000000000 +0000 +++ clementine-1.3.1-218/dist/windows/clementine-portable.nsi 2016-07-19 15:25:27.000000000 +0000 @@ -3,8 +3,8 @@ !define PRODUCT_PUBLISHER "Clementine" !define PRODUCT_VERSION_MAJOR 1 !define PRODUCT_VERSION_MINOR 3 -!define PRODUCT_DISPLAY_VERSION "1.3.1-217-g17beaa7" -!define PRODUCT_DISPLAY_VERSION_SHORT "1.3.1-217-g17beaa7" +!define PRODUCT_DISPLAY_VERSION "1.3.1-218-ga4e2eab" +!define PRODUCT_DISPLAY_VERSION_SHORT "1.3.1-218-ga4e2eab" !define PRODUCT_WEB_SITE "http://www.clementine-player.org/" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" @@ -104,7 +104,7 @@ !insertmacro MUI_LANGUAGE "Esperanto" Name "${PRODUCT_NAME}" -OutFile "${PRODUCT_NAME}Setup-1.3.1-217-g17beaa7.exe" +OutFile "${PRODUCT_NAME}Setup-1.3.1-218-ga4e2eab.exe" InstallDir "${PRODUCT_INSTALL_DIR}" ; Get the path where Clementine was installed previously and set it as default path