diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 943649f64..51d767af2 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -1133,7 +1133,7 @@ jobs: GST_SCANNER_PATH: /usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner GST_PLUGIN_PATH: /usr/local/lib/gstreamer-1.0 working-directory: build - run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_BUNDLE=ON -DUSE_SYSTEM_TAGLIB=OFF + run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_BUNDLE=ON - name: Build working-directory: build shell: bash @@ -1180,8 +1180,6 @@ jobs: -DENABLE_IMOBILEDEVICE=OFF -DENABLE_LIBMTP=OFF -DENABLE_XINE=OFF - -DUSE_SYSTEM_SINGLEAPPLICATION=OFF - -DUSE_SYSTEM_TAGLIB=OFF -DProtobuf_PROTOC_EXECUTABLE=/usr/src/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc - name: Run Make diff --git a/.travis.yml b/.travis.yml index 8747102bc..2c4a01ab9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ before_install: fi before_script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DUSE_BUNDLE=ON -DUSE_SYSTEM_TAGLIB=OFF ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DUSE_BUNDLE=ON ; fi script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then diff --git a/3rdparty/taglib/CMakeLists.txt b/3rdparty/taglib/CMakeLists.txt index 39d10106f..e79148ec2 100644 --- a/3rdparty/taglib/CMakeLists.txt +++ b/3rdparty/taglib/CMakeLists.txt @@ -8,17 +8,9 @@ math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSI math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}") math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}") -include(TestBigEndian) -test_big_endian(IS_BIG_ENDIAN) - -if(NOT IS_BIG_ENDIAN) - add_definitions(-DSYSTEM_BYTEORDER=1) -else() - add_definitions(-DSYSTEM_BYTEORDER=2) -endif() - include(ConfigureChecks.cmake) -configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h") +set(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests/taglib/") +configure_file(taglib-config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.h") add_definitions(-DHAVE_CONFIG_H) add_definitions(-DTAGLIB_STATIC) @@ -33,6 +25,7 @@ set(tag_HDRS toolkit/tlist.h toolkit/tlist.tcc toolkit/tstringlist.h + toolkit/tstringhandler.h toolkit/tbytevector.h toolkit/tbytevectorlist.h toolkit/tbytevectorstream.h @@ -41,6 +34,8 @@ set(tag_HDRS toolkit/tfilestream.h toolkit/tmap.h toolkit/tmap.tcc + toolkit/tpicture.h + toolkit/tpicturemap.h toolkit/tpropertymap.h toolkit/trefcounter.h toolkit/tdebuglistener.h @@ -300,8 +295,10 @@ set(dsdiff_SRCS ) set(toolkit_SRCS + toolkit/taglib.cpp toolkit/tstring.cpp toolkit/tstringlist.cpp + toolkit/tstringhandler.cpp toolkit/tbytevector.cpp toolkit/tbytevectorlist.cpp toolkit/tbytevectorstream.cpp @@ -309,6 +306,8 @@ set(toolkit_SRCS toolkit/tfile.cpp toolkit/tfilestream.cpp toolkit/tdebug.cpp + toolkit/tpicture.cpp + toolkit/tpicturemap.cpp toolkit/tpropertymap.cpp toolkit/trefcounter.cpp toolkit/tdebuglistener.cpp diff --git a/3rdparty/taglib/ape/apefile.cpp b/3rdparty/taglib/ape/apefile.cpp index 9ed21dfda..a7ad2cce4 100644 --- a/3rdparty/taglib/ape/apefile.cpp +++ b/3rdparty/taglib/ape/apefile.cpp @@ -31,14 +31,16 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include "tbytevector.h" +#include "tstring.h" +#include "tdebug.h" +#include "tagunion.h" +#include "id3v1tag.h" +#include "id3v2header.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "apefile.h" #include "apetag.h" @@ -56,42 +58,33 @@ class APE::File::FilePrivate { FilePrivate() : APELocation(-1), APESize(0), ID3v1Location(-1), - ID3v2Header(nullptr), ID3v2Location(-1), - ID3v2Size(0), - properties(nullptr) {} + ID3v2Size(0) {} - ~FilePrivate() { - delete ID3v2Header; - delete properties; - } + long long APELocation; + long long APESize; - long APELocation; - long APESize; + long long ID3v1Location; - long ID3v1Location; + std::unique_ptr ID3v2Header; + long long ID3v2Location; + long long ID3v2Size; - ID3v2::Header *ID3v2Header; - long ID3v2Location; - long ID3v2Size; + DoubleTagUnion tag; - TagUnion tag; - - AudioProperties *properties; + std::unique_ptr properties; }; //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// -bool APE::File::isSupported(IOStream *) { +bool APE::File::isSupported(IOStream *stream) { // An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede. - // FIXME: - //const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); - //return (buffer.find("MAC ") >= 0); + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); + return (buffer.find("MAC ") != ByteVector::npos()); - return false; } //////////////////////////////////////////////////////////////////////////////// @@ -120,14 +113,6 @@ Strawberry_TagLib::TagLib::Tag *APE::File::tag() const { return &d->tag; } -PropertyMap APE::File::properties() const { - return d->tag.properties(); -} - -void APE::File::removeUnsupportedProperties(const StringList &properties) { - d->tag.removeUnsupportedProperties(properties); -} - PropertyMap APE::File::setProperties(const PropertyMap &properties) { if (ID3v1Tag()) @@ -138,7 +123,7 @@ PropertyMap APE::File::setProperties(const PropertyMap &properties) { } APE::AudioProperties *APE::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool APE::File::save() { @@ -255,7 +240,7 @@ void APE::File::read(bool readProperties) { if (d->ID3v2Location >= 0) { seek(d->ID3v2Location); - d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); + d->ID3v2Header.reset(new ID3v2::Header(readBlock(ID3v2::Header::size()))); d->ID3v2Size = d->ID3v2Header->completeTagSize(); } @@ -283,7 +268,7 @@ void APE::File::read(bool readProperties) { if (readProperties) { - long streamLength; + long long streamLength; if (d->APELocation >= 0) streamLength = d->APELocation; @@ -300,7 +285,7 @@ void APE::File::read(bool readProperties) { seek(0); } - d->properties = new AudioProperties(this, streamLength); + d->properties.reset(new AudioProperties(this, streamLength)); } } diff --git a/3rdparty/taglib/ape/apefile.h b/3rdparty/taglib/ape/apefile.h index cd8eea4ab..8064b314b 100644 --- a/3rdparty/taglib/ape/apefile.h +++ b/3rdparty/taglib/ape/apefile.h @@ -107,36 +107,25 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. This will be an APE tag, an ID3v1 tag or a combination of the two. */ - virtual Strawberry_TagLib::TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both an APE and an ID3v1 tag, only APE will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function. - */ - void removeUnsupportedProperties(const StringList &properties); + Strawberry_TagLib::TagLib::Tag *tag() const override; /*! * Implements the unified property interface -- import function. * Creates an APEv2 tag if necessary. * A potentially existing ID3v1 tag will be updated as well. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap&) override; /*! * Returns the APE::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Saves the file. @@ -144,7 +133,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \note According to the official Monkey's Audio SDK, an APE file * can only have either ID3V1 or APE tags, so a parameter is used here. */ - virtual bool save(); + bool save() override; /*! * Returns a pointer to the ID3v1 tag of the file. @@ -210,7 +199,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File &); + File(const File &); File &operator=(const File &); void read(bool readProperties); diff --git a/3rdparty/taglib/ape/apefooter.cpp b/3rdparty/taglib/ape/apefooter.cpp index ccc031fb4..50fccd53a 100644 --- a/3rdparty/taglib/ape/apefooter.cpp +++ b/3rdparty/taglib/ape/apefooter.cpp @@ -27,8 +27,8 @@ #include #include -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "apefooter.h" @@ -155,19 +155,19 @@ void APE::Footer::parse(const ByteVector &data) { // Read the version number - d->version = data.toUInt(8, false); + d->version = data.toUInt32LE(8); // Read the tag size - d->tagSize = data.toUInt(12, false); + d->tagSize = data.toUInt32LE(12); // Read the item count - d->itemCount = data.toUInt(16, false); + d->itemCount = data.toUInt32LE(16); // Read the flags - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false))); + std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt32LE(20))); d->headerPresent = flags[31]; d->footerPresent = !flags[30]; @@ -186,15 +186,15 @@ ByteVector APE::Footer::render(bool isHeader) const { // add the version number -- we always render a 2.000 tag regardless of what // the tag originally was. - v.append(ByteVector::fromUInt(2000, false)); + v.append(ByteVector::fromUInt32LE(2000)); // add the tag size - v.append(ByteVector::fromUInt(d->tagSize, false)); + v.append(ByteVector::fromUInt32LE(d->tagSize)); // add the item count - v.append(ByteVector::fromUInt(d->itemCount, false)); + v.append(ByteVector::fromUInt32LE(d->itemCount)); // render and add the flags @@ -204,11 +204,11 @@ ByteVector APE::Footer::render(bool isHeader) const { flags[30] = false; // footer is always present flags[29] = isHeader; - v.append(ByteVector::fromUInt(flags.to_ulong(), false)); + v.append(ByteVector::fromUInt32LE(flags.to_ulong())); // add the reserved 64bit - v.append(ByteVector::fromLongLong(0)); + v.append(ByteVector::fromUInt64BE(0)); return v; diff --git a/3rdparty/taglib/ape/apefooter.h b/3rdparty/taglib/ape/apefooter.h index b4f9774e1..6e39900b0 100644 --- a/3rdparty/taglib/ape/apefooter.h +++ b/3rdparty/taglib/ape/apefooter.h @@ -161,7 +161,7 @@ class TAGLIB_EXPORT Footer { ByteVector render(bool isHeader) const; private: - explicit Footer(const Footer &); + Footer(const Footer &); Footer &operator=(const Footer &); class FooterPrivate; diff --git a/3rdparty/taglib/ape/apeitem.cpp b/3rdparty/taglib/ape/apeitem.cpp index 8d50383f1..682c3ccf4 100644 --- a/3rdparty/taglib/ape/apeitem.cpp +++ b/3rdparty/taglib/ape/apeitem.cpp @@ -23,17 +23,18 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include + +#include "tbytevectorlist.h" +#include "tdebug.h" #include "apeitem.h" using namespace Strawberry_TagLib::TagLib; using namespace APE; -class APE::Item::ItemPrivate { - public: - ItemPrivate() : type(Text), readOnly(false) {} +struct ItemData { + ItemData() : type(Item::Text), readOnly(false) {} Item::ItemTypes type; String key; @@ -42,26 +43,37 @@ class APE::Item::ItemPrivate { bool readOnly; }; +class APE::Item::ItemPrivate { + public: + ItemPrivate() : data(new ItemData()) {} + + std::shared_ptr data; +}; + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// APE::Item::Item() : d(new ItemPrivate()) {} +APE::Item::Item(const String &key, const String &value) : d(new ItemPrivate()) { + d->data->key = key; + d->data->text.append(value); +} + APE::Item::Item(const String &key, const StringList &values) : d(new ItemPrivate()) { - d->key = key; - d->text = values; + d->data->key = key; + d->data->text = values; } APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new ItemPrivate()) { - - d->key = key; + d->data->key = key; if (binary) { - d->type = Binary; - d->value = value; + d->data->type = Binary; + d->data->value = value; } else { - d->text.append(value); + d->data->text.append(value); } } @@ -88,126 +100,109 @@ void APE::Item::swap(Item &item) { } void APE::Item::setReadOnly(bool readOnly) { - d->readOnly = readOnly; + d->data->readOnly = readOnly; } bool APE::Item::isReadOnly() const { - return d->readOnly; + return d->data->readOnly; } -void APE::Item::setType(APE::Item::ItemTypes type) { - d->type = type; +void APE::Item::setType(APE::Item::ItemTypes val) { + d->data->type = val; } APE::Item::ItemTypes APE::Item::type() const { - return d->type; + return d->data->type; } String APE::Item::key() const { - return d->key; + return d->data->key; } ByteVector APE::Item::binaryData() const { - return d->value; + return d->data->value; } void APE::Item::setBinaryData(const ByteVector &value) { - - d->type = Binary; - d->value = value; - d->text.clear(); - + d->data->type = Binary; + d->data->value = value; + d->data->text.clear(); } void APE::Item::setKey(const String &key) { - d->key = key; + d->data->key = key; } void APE::Item::setValue(const String &value) { - - d->type = Text; - d->text = value; - d->value.clear(); - + d->data->type = Text; + d->data->text = value; + d->data->value.clear(); } void APE::Item::setValues(const StringList &value) { - - d->type = Text; - d->text = value; - d->value.clear(); - + d->data->type = Text; + d->data->text = value; + d->data->value.clear(); } void APE::Item::appendValue(const String &value) { - - d->type = Text; - d->text.append(value); - d->value.clear(); - + d->data->type = Text; + d->data->text.append(value); + d->data->value.clear(); } void APE::Item::appendValues(const StringList &values) { - - d->type = Text; - d->text.append(values); - d->value.clear(); - + d->data->type = Text; + d->data->text.append(values); + d->data->value.clear(); } int APE::Item::size() const { - - int result = 8 + d->key.size() + 1; - switch (d->type) { + size_t result = 8 + d->data->key.size() + 1; + switch (d->data->type) { case Text: - if (!d->text.isEmpty()) { - StringList::ConstIterator it = d->text.begin(); + if (!d->data->text.isEmpty()) { + StringList::ConstIterator it = d->data->text.begin(); result += it->data(String::UTF8).size(); it++; - for (; it != d->text.end(); ++it) + for (; it != d->data->text.end(); ++it) result += 1 + it->data(String::UTF8).size(); } break; case Binary: case Locator: - result += d->value.size(); + result += d->data->value.size(); break; } return result; } -StringList APE::Item::toStringList() const { - return d->text; -} - StringList APE::Item::values() const { - return d->text; + return d->data->text; } String APE::Item::toString() const { - - if (d->type == Text && !isEmpty()) - return d->text.front(); + if (d->data->type == Text && !isEmpty()) + return d->data->text.front(); else return String(); } bool APE::Item::isEmpty() const { - - switch (d->type) { + switch (d->data->type) { case Text: - if (d->text.isEmpty()) + if (d->data->text.isEmpty()) return true; - if (d->text.size() == 1 && d->text.front().isEmpty()) + if (d->data->text.size() == 1 && d->data->text.front().isEmpty()) return true; return false; case Binary: case Locator: - return d->value.isEmpty(); + return d->data->value.isEmpty(); default: return false; } @@ -223,52 +218,51 @@ void APE::Item::parse(const ByteVector &data) { return; } - const unsigned int valueLength = data.toUInt(0, false); - const unsigned int flags = data.toUInt(4, false); + const unsigned int valueLength = data.toUInt32LE(0); + const unsigned int flags = data.toUInt32LE(4); // 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[8], String::Latin1); + d->data->key = String(&data[8], String::Latin1); - const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength); + const ByteVector value = data.mid(8 + d->data->key.size() + 1, valueLength); setReadOnly(flags & 1); setType(ItemTypes((flags >> 1) & 3)); - if (Text == d->type) - d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8); + if (Text == d->data->type) + d->data->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8); else - d->value = value; - + d->data->value = value; } ByteVector APE::Item::render() const { ByteVector data; - unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); + unsigned int flags = ((d->data->readOnly) ? 1 : 0) | (d->data->type << 1); ByteVector value; if (isEmpty()) return data; - if (d->type == Text) { - StringList::ConstIterator it = d->text.begin(); + if (d->data->type == Text) { + StringList::ConstIterator it = d->data->text.begin(); value.append(it->data(String::UTF8)); it++; - for (; it != d->text.end(); ++it) { + for (; it != d->data->text.end(); ++it) { value.append('\0'); value.append(it->data(String::UTF8)); } - d->value = value; + d->data->value = value; } else - value.append(d->value); + value.append(d->data->value); - data.append(ByteVector::fromUInt(value.size(), false)); - data.append(ByteVector::fromUInt(flags, false)); - data.append(d->key.data(String::Latin1)); + data.append(ByteVector::fromUInt32LE(value.size())); + data.append(ByteVector::fromUInt32LE(flags)); + data.append(d->data->key.data(String::Latin1)); data.append(ByteVector('\0')); data.append(value); diff --git a/3rdparty/taglib/ape/apeitem.h b/3rdparty/taglib/ape/apeitem.h index aa975c857..75a5bf000 100644 --- a/3rdparty/taglib/ape/apeitem.h +++ b/3rdparty/taglib/ape/apeitem.h @@ -57,6 +57,11 @@ class TAGLIB_EXPORT Item { */ explicit Item(); + /*! + * Constructs a text item with \a key and \a values. + */ + explicit Item(const String &key, const String &values); + /*! * Constructs a text item with \a key and \a values. */ @@ -71,7 +76,7 @@ class TAGLIB_EXPORT Item { /*! * Construct an item as a copy of \a item. */ - explicit Item(const Item &item); + Item(const Item &item); /*! * Destroys the item. @@ -148,7 +153,6 @@ class TAGLIB_EXPORT Item { * If the data type is not \a Text, always returns an empty String. */ String toString() const; - StringList toStringList() const; /*! * Returns the list of text values. If the data type is not \a Text, always returns an empty StringList. diff --git a/3rdparty/taglib/ape/apeproperties.cpp b/3rdparty/taglib/ape/apeproperties.cpp index 98448cb66..3ab702e8d 100644 --- a/3rdparty/taglib/ape/apeproperties.cpp +++ b/3rdparty/taglib/ape/apeproperties.cpp @@ -27,9 +27,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" + #include "id3v2tag.h" #include "apeproperties.h" #include "apefile.h" @@ -40,13 +40,13 @@ using namespace Strawberry_TagLib::TagLib; class APE::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - channels(0), - version(0), - bitsPerSample(0), - sampleFrames(0) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + version(0), + bitsPerSample(0), + sampleFrames(0) {} int length; int bitrate; @@ -61,7 +61,7 @@ class APE::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -APE::AudioProperties::AudioProperties(File *file, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +APE::AudioProperties::AudioProperties(File *file, long long streamLength, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file, streamLength); } @@ -110,14 +110,14 @@ int headerVersion(const ByteVector &header) { if (header.size() < 6 || !header.startsWith("MAC ")) return -1; - return header.toUShort(4, false); + return header.toUInt16LE(4); } } // namespace -void APE::AudioProperties::read(File *file, long streamLength) { +void APE::AudioProperties::read(File *file, long long streamLength) { // First, we assume that the file pointer is set at the first descriptor. - long offset = file->tell(); + long long offset = file->tell(); int version = headerVersion(file->readBlock(6)); // Next, we look for the descriptor. @@ -157,7 +157,7 @@ void APE::AudioProperties::analyzeCurrent(File *file) { return; } - const unsigned int descriptorBytes = descriptor.toUInt(0, false); + const unsigned int descriptorBytes = descriptor.toUInt32LE(0); if ((descriptorBytes - 52) > 0) file->seek(descriptorBytes - 52, File::Current); @@ -170,16 +170,16 @@ void APE::AudioProperties::analyzeCurrent(File *file) { } // Get the APE info - d->channels = header.toShort(18, false); - d->sampleRate = header.toUInt(20, false); - d->bitsPerSample = header.toShort(16, false); + d->channels = header.toUInt16LE(18); + d->sampleRate = header.toUInt32LE(20); + d->bitsPerSample = header.toUInt16LE(16); - const unsigned int totalFrames = header.toUInt(12, false); + const unsigned int totalFrames = header.toUInt32LE(12); if (totalFrames == 0) return; - const unsigned int blocksPerFrame = header.toUInt(4, false); - const unsigned int finalFrameBlocks = header.toUInt(8, false); + const unsigned int blocksPerFrame = header.toUInt32LE(4); + const unsigned int finalFrameBlocks = header.toUInt32LE(8); d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks; } @@ -192,13 +192,13 @@ void APE::AudioProperties::analyzeOld(File *file) { return; } - const unsigned int totalFrames = header.toUInt(18, false); + const unsigned int totalFrames = header.toUInt32LE(18); // Fail on 0 length APE files (catches non-finalized APE files) if (totalFrames == 0) return; - const short compressionLevel = header.toShort(0, false); + const short compressionLevel = header.toUInt32LE(0); unsigned int blocksPerFrame; if (d->version >= 3950) blocksPerFrame = 73728 * 4; @@ -208,10 +208,10 @@ void APE::AudioProperties::analyzeOld(File *file) { blocksPerFrame = 9216; // Get the APE info - d->channels = header.toShort(4, false); - d->sampleRate = header.toUInt(6, false); + d->channels = header.toUInt16LE(4); + d->sampleRate = header.toUInt32LE(6); - const unsigned int finalFrameBlocks = header.toUInt(22, false); + const unsigned int finalFrameBlocks = header.toUInt32LE(22); d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks; // Get the bit depth from the RIFF-fmt chunk. @@ -222,6 +222,6 @@ void APE::AudioProperties::analyzeOld(File *file) { return; } - d->bitsPerSample = fmt.toShort(26, false); + d->bitsPerSample = fmt.toUInt16LE(26); } diff --git a/3rdparty/taglib/ape/apeproperties.h b/3rdparty/taglib/ape/apeproperties.h index b5a9aa7dd..02f2a77e6 100644 --- a/3rdparty/taglib/ape/apeproperties.h +++ b/3rdparty/taglib/ape/apeproperties.h @@ -51,41 +51,41 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of APE::AudioProperties with the data read from the APE::File \a file. */ - explicit AudioProperties(File *file, long streamLength, ReadStyle style = Average); + explicit AudioProperties(File *file, long long streamLength, ReadStyle style = Average); /*! * Destroys this APE::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -103,10 +103,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int version() const; private: - explicit AudioProperties(const AudioProperties &); - AudioProperties &operator=(const AudioProperties &); - - void read(File *file, long streamLength); + void read(File *file, long long streamLength); void analyzeCurrent(File *file); void analyzeOld(File *file); diff --git a/3rdparty/taglib/ape/apetag.cpp b/3rdparty/taglib/ape/apetag.cpp index 00a518467..0b43a0b63 100644 --- a/3rdparty/taglib/ape/apetag.cpp +++ b/3rdparty/taglib/ape/apetag.cpp @@ -31,12 +31,13 @@ # define WANT_CLASS_INSTANTIATION_OF_MAP (1) #endif -#include -#include -#include -#include -#include -#include +#include "tfile.h" +#include "tstring.h" +#include "tmap.h" +#include "tpicturemap.h" +#include "tpropertymap.h" +#include "tdebug.h" +#include "tutils.h" #include "apetag.h" #include "apefooter.h" @@ -76,7 +77,7 @@ class APE::Tag::TagPrivate { TagPrivate() : file(nullptr), footerLocation(0) {} File *file; - long footerLocation; + long long footerLocation; Footer footer; ItemListMap itemListMap; @@ -88,7 +89,7 @@ class APE::Tag::TagPrivate { APE::Tag::Tag() : d(new TagPrivate()) {} -APE::Tag::Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation) : d(new TagPrivate()) { +APE::Tag::Tag(Strawberry_TagLib::TagLib::File *file, long long footerLocation) : d(new TagPrivate()) { d->file = file; d->footerLocation = footerLocation; @@ -160,6 +161,43 @@ unsigned int APE::Tag::track() const { } +Strawberry_TagLib::TagLib::PictureMap APE::Tag::pictures() const { + + PictureMap map; + if (d->itemListMap.contains(FRONT_COVER)) { + Item front = d->itemListMap[FRONT_COVER]; + if (Item::Binary == front.type()) { + ByteVector picture = front.binaryData(); + const size_t index = picture.find('\0'); + if (index < picture.size()) { + ByteVector desc = picture.mid(0, index + 1); + String mime = "image/jpeg"; + ByteVector data = picture.mid(index + 1); + Picture p(data, Picture::FrontCover, mime, desc); + map.insert(p); + } + } + } + + if (d->itemListMap.contains(BACK_COVER)) { + Item back = d->itemListMap[BACK_COVER]; + if (Item::Binary == back.type()) { + ByteVector picture = back.binaryData(); + const size_t index = picture.find('\0'); + if (index < picture.size()) { + ByteVector desc = picture.mid(0, index + 1); + String mime = "image/jpeg"; + ByteVector data = picture.mid(index + 1); + Picture p(data, Picture::BackCover, mime, desc); + map.insert(p); + } + } + } + + return PictureMap(map); + +} + void APE::Tag::setTitle(const String &s) { addValue("TITLE", s, true); } @@ -181,17 +219,72 @@ void APE::Tag::setGenre(const String &s) { } void APE::Tag::setYear(unsigned int i) { + if (i == 0) removeItem("YEAR"); else addValue("YEAR", String::number(i), true); + } void APE::Tag::setTrack(unsigned int i) { + if (i == 0) removeItem("TRACK"); else addValue("TRACK", String::number(i), true); + +} + +void APE::Tag::setPictures(const PictureMap &l) { + + removeItem(FRONT_COVER); + removeItem(BACK_COVER); + + for (PictureMap::ConstIterator pictureMapIt = l.begin(); pictureMapIt != l.end(); ++pictureMapIt) { + Picture::Type type = pictureMapIt->first; + if (Picture::FrontCover != type && Picture::BackCover != type) { + std::cout << "APE: Trying to add a picture with wrong type" << std::endl; + continue; + } + + const char *id; + switch (type) { + case Picture::FrontCover: + id = FRONT_COVER; + break; + case Picture::BackCover: + id = BACK_COVER; + break; + default: + id = FRONT_COVER; + break; + } + + PictureList list = pictureMapIt->second; + for (PictureList::ConstIterator pictureListIt = list.begin(); pictureListIt != list.end(); ++pictureListIt) { + Picture picture = *pictureListIt; + if (d->itemListMap.contains(id)) { + std::cout << "APE: Already added a picture of type " + << id + << " '" + << picture.description() + << "' " + << "and next are being ignored" + << std::endl; + break; + } + + ByteVector data = picture.description().data(String::Latin1).append('\0').append(picture.data()); + + Item item; + item.setKey(id); + item.setType(Item::Binary); + item.setBinaryData(data); + setItem(item.key(), item); + } + } + } namespace { @@ -223,7 +316,7 @@ PropertyMap APE::Tag::properties() const { if (tagName == keyConversions[i][1]) tagName = keyConversions[i][0]; } - properties[tagName].append(it->second.toStringList()); + properties[tagName].append(it->second.values()); } } return properties; @@ -397,18 +490,18 @@ void APE::Tag::parse(const ByteVector &data) { if (data.size() < 11) return; - unsigned int pos = 0; + size_t pos = 0; 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) { + const size_t nullPos = data.find('\0', pos + 8); + if (nullPos == ByteVector::npos()) { debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing."); return; } - const unsigned int keyLength = nullPos - pos - 8; - const unsigned int valLegnth = data.toUInt(pos, false); + const size_t keyLength = nullPos - pos - 8; + const size_t valLegnth = data.toUInt32LE(pos); if (keyLength >= MinKeyLength && keyLength <= MaxKeyLength && isKeyValid(data.mid(pos + 8, keyLength))) { APE::Item item; diff --git a/3rdparty/taglib/ape/apetag.h b/3rdparty/taglib/ape/apetag.h index 50c60a541..713e04e2a 100644 --- a/3rdparty/taglib/ape/apetag.h +++ b/3rdparty/taglib/ape/apetag.h @@ -34,6 +34,9 @@ #include "apeitem.h" +#define FRONT_COVER "COVER ART (FRONT)" +#define BACK_COVER "COVER ART (BACK)" + namespace Strawberry_TagLib { namespace TagLib { @@ -50,7 +53,7 @@ class Footer; * * \see APE::Tag::itemListMap() */ -typedef Map ItemListMap; +typedef Map ItemListMap; //! An APE tag implementation @@ -66,12 +69,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * Create an APE tag and parse the data in \a file with APE footer at * \a tagOffset. */ - explicit Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation); + explicit Tag(Strawberry_TagLib::TagLib::File *file, long long footerLocation); /*! * Destroys this Tag instance. */ - virtual ~Tag(); + ~Tag() override; /*! * Renders the in memory values to a ByteVector suitable for writing to the file. @@ -85,21 +88,31 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { // Reimplementations. - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; - 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(unsigned int i); - virtual void setTrack(unsigned int i); + /** + * @brief pictures + * According to : + * http://www.hydrogenaud.io/forums/index.php?showtopic=40603&st=50&p=504669&#entry504669 + * http://git.videolan.org/?p=vlc.git;a=blob;f=modules/meta_engine/taglib.cpp + * @return + */ + PictureMap pictures() const override; + + void setTitle(const String &s) override; + void setArtist(const String &s) override; + void setAlbum(const String &s) override; + void setComment(const String &s) override; + void setGenre(const String &s) override; + void setYear(unsigned int i) override; + void setTrack(unsigned int i) override; + void setPictures(const PictureMap &l) override; /*! * Implements the unified tag dictionary interface -- export function. @@ -114,9 +127,9 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, * respectively, in order to be compliant with the names used in other formats. */ - PropertyMap properties() const; + PropertyMap properties() const override; - void removeUnsupportedProperties(const StringList &properties); + void removeUnsupportedProperties(const StringList &properties) override; /*! * Implements the unified tag dictionary interface -- import function. @@ -124,7 +137,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * specification requires keys to have between 2 and 16 printable ASCII characters * with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+". */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; /*! * Check if the given String is a valid APE tag key. @@ -176,7 +189,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { /*! * Returns true if the tag does not contain any data. */ - bool isEmpty() const; + bool isEmpty() const override; protected: /*! @@ -190,7 +203,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { void parse(const ByteVector &data); private: - explicit Tag(const Tag &); + Tag(const Tag &); Tag &operator=(const Tag &); class TagPrivate; diff --git a/3rdparty/taglib/asf/asfattribute.cpp b/3rdparty/taglib/asf/asfattribute.cpp index 18a1522f8..36b77b762 100644 --- a/3rdparty/taglib/asf/asfattribute.cpp +++ b/3rdparty/taglib/asf/asfattribute.cpp @@ -23,9 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include + +#include "taglib.h" +#include "tdebug.h" #include "asfattribute.h" #include "asffile.h" @@ -33,10 +34,11 @@ using namespace Strawberry_TagLib::TagLib; -class ASF::Attribute::AttributePrivate : public RefCounter { - public: - AttributePrivate() : pictureValue(ASF::Picture::fromInvalid()), numericValue(0), stream(0), language(0) {} - AttributeTypes type; +namespace { +struct AttributeData { + explicit AttributeData() : numericValue(0), stream(0), language(0) {} + + ASF::Attribute::AttributeTypes type; String stringValue; ByteVector byteVectorValue; ASF::Picture pictureValue; @@ -44,52 +46,60 @@ class ASF::Attribute::AttributePrivate : public RefCounter { int stream; int language; }; +} // namespace + +class ASF::Attribute::AttributePrivate { + public: + AttributePrivate() : data(new AttributeData()) { + data->pictureValue = ASF::Picture::fromInvalid(); + } + + std::shared_ptr data; +}; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// ASF::Attribute::Attribute() : d(new AttributePrivate()) { - d->type = UnicodeType; + d->data->type = UnicodeType; } -ASF::Attribute::Attribute(const ASF::Attribute &other) : d(other.d) { - d->ref(); -} +ASF::Attribute::Attribute(const ASF::Attribute &other) : d(new AttributePrivate(*other.d)) {} ASF::Attribute::Attribute(const String &value) : d(new AttributePrivate()) { - d->type = UnicodeType; - d->stringValue = value; + d->data->type = UnicodeType; + d->data->stringValue = value; } ASF::Attribute::Attribute(const ByteVector &value) : d(new AttributePrivate()) { - d->type = BytesType; - d->byteVectorValue = value; + d->data->type = BytesType; + d->data->byteVectorValue = value; } ASF::Attribute::Attribute(const ASF::Picture &value) : d(new AttributePrivate()) { - d->type = BytesType; - d->pictureValue = value; + d->data->type = BytesType; + d->data->pictureValue = value; } ASF::Attribute::Attribute(unsigned int value) : d(new AttributePrivate()) { - d->type = DWordType; - d->numericValue = value; + d->data->type = DWordType; + d->data->numericValue = value; } ASF::Attribute::Attribute(unsigned long long value) : d(new AttributePrivate()) { - d->type = QWordType; - d->numericValue = value; + d->data->type = QWordType; + d->data->numericValue = value; } ASF::Attribute::Attribute(unsigned short value) : d(new AttributePrivate()) { - d->type = WordType; - d->numericValue = value; + d->data->type = WordType; + d->data->numericValue = value; } ASF::Attribute::Attribute(bool value) : d(new AttributePrivate()) { - d->type = BoolType; - d->numericValue = value; + d->data->type = BoolType; + d->data->numericValue = value; } ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) { @@ -104,54 +114,54 @@ void ASF::Attribute::swap(Attribute &other) { } ASF::Attribute::~Attribute() { - if (d->deref()) - delete d; + delete d; } ASF::Attribute::AttributeTypes ASF::Attribute::type() const { - return d->type; + return d->data->type; } String ASF::Attribute::toString() const { - return d->stringValue; + return d->data->stringValue; } ByteVector ASF::Attribute::toByteVector() const { - if (d->pictureValue.isValid()) - return d->pictureValue.render(); - return d->byteVectorValue; + if (d->data->pictureValue.isValid()) + return d->data->pictureValue.render(); + + return d->data->byteVectorValue; } unsigned short ASF::Attribute::toBool() const { - return d->numericValue ? 1 : 0; + return d->data->numericValue ? 1 : 0; } unsigned short ASF::Attribute::toUShort() const { - return static_cast(d->numericValue); + return static_cast(d->data->numericValue); } unsigned int ASF::Attribute::toUInt() const { - return static_cast(d->numericValue); + return static_cast(d->data->numericValue); } unsigned long long ASF::Attribute::toULongLong() const { - return static_cast(d->numericValue); + return static_cast(d->data->numericValue); } ASF::Picture ASF::Attribute::toPicture() const { - return d->pictureValue; + return d->data->pictureValue; } String ASF::Attribute::parse(ASF::File &f, int kind) { unsigned int size, nameLength; String name; - d->pictureValue = Picture::fromInvalid(); + d->data->pictureValue = Picture::fromInvalid(); // extended content descriptor if (kind == 0) { nameLength = readWORD(&f); name = readString(&f, nameLength); - d->type = ASF::Attribute::AttributeTypes(readWORD(&f)); + d->data->type = ASF::Attribute::AttributeTypes(readWORD(&f)); size = readWORD(&f); } // metadata & metadata library @@ -159,11 +169,11 @@ String ASF::Attribute::parse(ASF::File &f, int kind) { int temp = readWORD(&f); // metadata library if (kind == 2) { - d->language = temp; + d->data->language = temp; } - d->stream = readWORD(&f); + d->data->stream = readWORD(&f); nameLength = readWORD(&f); - d->type = ASF::Attribute::AttributeTypes(readWORD(&f)); + d->data->type = ASF::Attribute::AttributeTypes(readWORD(&f)); size = readDWORD(&f); name = readString(&f, nameLength); } @@ -172,42 +182,42 @@ String ASF::Attribute::parse(ASF::File &f, int kind) { debug("ASF::Attribute::parse() -- Value larger than 64kB"); } - switch (d->type) { + switch (d->data->type) { case WordType: - d->numericValue = readWORD(&f); + d->data->numericValue = readWORD(&f); break; case BoolType: if (kind == 0) { - d->numericValue = (readDWORD(&f) != 0); + d->data->numericValue = (readDWORD(&f) != 0); } else { - d->numericValue = (readWORD(&f) != 0); + d->data->numericValue = (readWORD(&f) != 0); } break; case DWordType: - d->numericValue = readDWORD(&f); + d->data->numericValue = readDWORD(&f); break; case QWordType: - d->numericValue = readQWORD(&f); + d->data->numericValue = readQWORD(&f); break; case UnicodeType: - d->stringValue = readString(&f, size); + d->data->stringValue = readString(&f, size); break; case BytesType: case GuidType: - d->byteVectorValue = f.readBlock(size); + d->data->byteVectorValue = f.readBlock(size); break; } - if (d->type == BytesType && name == "WM/Picture") { - d->pictureValue.parse(d->byteVectorValue); - if (d->pictureValue.isValid()) { - d->byteVectorValue.clear(); + if (d->data->type == BytesType && name == "WM/Picture") { + d->data->pictureValue.parse(d->data->byteVectorValue); + if (d->data->pictureValue.isValid()) { + d->data->byteVectorValue.clear(); } } @@ -217,7 +227,7 @@ String ASF::Attribute::parse(ASF::File &f, int kind) { int ASF::Attribute::dataSize() const { - switch (d->type) { + switch (d->data->type) { case WordType: return 2; case BoolType: @@ -227,13 +237,13 @@ int ASF::Attribute::dataSize() const { case QWordType: return 5; case UnicodeType: - return d->stringValue.size() * 2 + 2; + return static_cast(d->data->stringValue.size() * 2 + 2); case BytesType: - if (d->pictureValue.isValid()) - return d->pictureValue.dataSize(); + if (d->data->pictureValue.isValid()) + return d->data->pictureValue.dataSize(); break; case GuidType: - return d->byteVectorValue.size(); + return static_cast(d->data->byteVectorValue.size()); } return 0; @@ -243,56 +253,56 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const { ByteVector data; - switch (d->type) { + switch (d->data->type) { case WordType: - data.append(ByteVector::fromShort(toUShort(), false)); + data.append(ByteVector::fromUInt16LE(toUShort())); break; case BoolType: if (kind == 0) { - data.append(ByteVector::fromUInt(toBool(), false)); + data.append(ByteVector::fromUInt32LE(toBool())); } else { - data.append(ByteVector::fromShort(toBool(), false)); + data.append(ByteVector::fromUInt16LE(toBool())); } break; case DWordType: - data.append(ByteVector::fromUInt(toUInt(), false)); + data.append(ByteVector::fromUInt32LE(toUInt())); break; case QWordType: - data.append(ByteVector::fromLongLong(toULongLong(), false)); + data.append(ByteVector::fromUInt64LE(toULongLong())); break; case UnicodeType: - data.append(renderString(d->stringValue)); + data.append(renderString(d->data->stringValue)); break; case BytesType: - if (d->pictureValue.isValid()) { - data.append(d->pictureValue.render()); + if (d->data->pictureValue.isValid()) { + data.append(d->data->pictureValue.render()); break; } break; case GuidType: - data.append(d->byteVectorValue); + data.append(d->data->byteVectorValue); break; } if (kind == 0) { data = renderString(name, true) + - ByteVector::fromShort(static_cast(d->type), false) + - ByteVector::fromShort(data.size(), false) + + ByteVector::fromUInt16LE((int)d->data->type) + + ByteVector::fromUInt16LE(data.size()) + data; } else { ByteVector nameData = renderString(name); - data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) + - ByteVector::fromShort(d->stream, false) + - ByteVector::fromShort(nameData.size(), false) + - ByteVector::fromShort(static_cast(d->type), false) + - ByteVector::fromUInt(data.size(), false) + + data = ByteVector::fromUInt16LE(kind == 2 ? d->data->language : 0) + + ByteVector::fromUInt16LE(d->data->stream) + + ByteVector::fromUInt16LE(nameData.size()) + + ByteVector::fromUInt16LE(static_cast(d->data->type)) + + ByteVector::fromUInt32LE(data.size()) + nameData + data; } @@ -302,17 +312,17 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const { } int ASF::Attribute::language() const { - return d->language; + return d->data->language; } void ASF::Attribute::setLanguage(int value) { - d->language = value; + d->data->language = value; } int ASF::Attribute::stream() const { - return d->stream; + return d->data->stream; } void ASF::Attribute::setStream(int value) { - d->stream = value; + d->data->stream = value; } diff --git a/3rdparty/taglib/asf/asfattribute.h b/3rdparty/taglib/asf/asfattribute.h index 4b9ec6aeb..2da2f5908 100644 --- a/3rdparty/taglib/asf/asfattribute.h +++ b/3rdparty/taglib/asf/asfattribute.h @@ -56,7 +56,7 @@ class TAGLIB_EXPORT Attribute { /*! * Constructs an empty attribute. */ - explicit Attribute(); + Attribute(); /*! * Constructs an attribute with \a key and a UnicodeType \a value. @@ -66,7 +66,7 @@ class TAGLIB_EXPORT Attribute { /*! * Constructs an attribute with \a key and a BytesType \a value. */ - explicit Attribute(const ByteVector &value); + Attribute(const ByteVector &value); /*! * Constructs an attribute with \a key and a Picture \a value. @@ -79,27 +79,27 @@ class TAGLIB_EXPORT Attribute { * WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications. * You must add code in your application to perform validations if you want to maintain complete compatibility with ID3. */ - explicit Attribute(const Picture &value); + Attribute(const Picture &value); /*! * Constructs an attribute with \a key and a DWordType \a value. */ - explicit Attribute(unsigned int value); + Attribute(unsigned int value); /*! * Constructs an attribute with \a key and a QWordType \a value. */ - explicit Attribute(unsigned long long value); + Attribute(unsigned long long value); /*! * Constructs an attribute with \a key and a WordType \a value. */ - explicit Attribute(unsigned short value); + Attribute(unsigned short value); /*! * Constructs an attribute with \a key and a BoolType \a value. */ - explicit Attribute(bool value); + Attribute(bool value); /*! * Construct an attribute as a copy of \a other. @@ -181,17 +181,13 @@ class TAGLIB_EXPORT Attribute { */ void setStream(int value); -#ifndef DO_NOT_DOCUMENT - /* THIS IS PRIVATE, DON'T TOUCH IT! */ - String parse(ASF::File &file, int kind = 0); -#endif - //! Returns the size of the stored data int dataSize() const; private: friend class File; + String parse(ASF::File &file, int kind = 0); ByteVector render(const String &name, int kind = 0) const; class AttributePrivate; diff --git a/3rdparty/taglib/asf/asffile.cpp b/3rdparty/taglib/asf/asffile.cpp index 8da505131..687510789 100644 --- a/3rdparty/taglib/asf/asffile.cpp +++ b/3rdparty/taglib/asf/asffile.cpp @@ -23,11 +23,13 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include +#include + +#include "tdebug.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "tstring.h" +#include "tagutils.h" #include "asffile.h" #include "asftag.h" @@ -49,34 +51,23 @@ class ASF::File::FilePrivate { class MetadataObject; class MetadataLibraryObject; - FilePrivate() : headerSize(0), - tag(nullptr), - properties(nullptr), - contentDescriptionObject(nullptr), - extendedContentDescriptionObject(nullptr), - headerExtensionObject(nullptr), - metadataObject(nullptr), - metadataLibraryObject(nullptr) { - objects.setAutoDelete(true); - } + typedef List> ObjectList; + typedef ObjectList::ConstIterator ObjectConstIterator; - ~FilePrivate() { - delete tag; - delete properties; - } + FilePrivate() : headerSize(0) {} unsigned long long headerSize; - ASF::Tag *tag; - ASF::AudioProperties *properties; + std::unique_ptr tag; + std::unique_ptr properties; - List objects; + ObjectList objects; - ContentDescriptionObject *contentDescriptionObject; - ExtendedContentDescriptionObject *extendedContentDescriptionObject; - HeaderExtensionObject *headerExtensionObject; - MetadataObject *metadataObject; - MetadataLibraryObject *metadataLibraryObject; + std::shared_ptr contentDescriptionObject; + std::shared_ptr extendedContentDescriptionObject; + std::shared_ptr headerExtensionObject; + std::shared_ptr metadataObject; + std::shared_ptr metadataLibraryObject; }; namespace { @@ -156,7 +147,7 @@ class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePriv class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject { public: - List objects; + ObjectList objects; HeaderExtensionObject(); ByteVector guid() const override; void parse(ASF::File *file, unsigned int size) override; @@ -179,7 +170,7 @@ class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::B void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size) { data.clear(); - if (size > 24 && size <= static_cast(file->length())) + if (size > 24 && static_cast(size) <= file->length()) data = file->readBlock(size - 24); else data = ByteVector(); @@ -187,7 +178,7 @@ void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int siz } ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/) { - return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data; + return guid() + ByteVector::fromUInt64LE(data.size() + 24) + data; } ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid) {} @@ -208,8 +199,8 @@ void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsign return; } - const long long duration = data.toLongLong(40, false); - const long long preroll = data.toLongLong(56, false); + const long long duration = data.toInt64LE(40); + const long long preroll = data.toInt64LE(56); file->d->properties->setLengthInMilliseconds(static_cast(duration / 10000.0 - preroll + 0.5)); } @@ -226,11 +217,11 @@ void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsi return; } - file->d->properties->setCodec(data.toUShort(54, false)); - file->d->properties->setChannels(data.toUShort(56, false)); - file->d->properties->setSampleRate(data.toUInt(58, false)); - file->d->properties->setBitrate(static_cast(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5)); - file->d->properties->setBitsPerSample(data.toUShort(68, false)); + file->d->properties->setCodec(data.toUInt16LE(54)); + file->d->properties->setChannels(data.toUInt16LE(56)); + file->d->properties->setSampleRate(data.toUInt32LE(58)); + file->d->properties->setBitrate(static_cast(data.toUInt32LE(62) * 8.0 / 1000.0 + 0.5)); + file->d->properties->setBitsPerSample(data.toUInt16LE(68)); } @@ -261,11 +252,11 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *f const ByteVector v4 = renderString(file->d->tag->comment()); const ByteVector v5 = renderString(file->d->tag->rating()); data.clear(); - data.append(ByteVector::fromShort(v1.size(), false)); - data.append(ByteVector::fromShort(v2.size(), false)); - data.append(ByteVector::fromShort(v3.size(), false)); - data.append(ByteVector::fromShort(v4.size(), false)); - data.append(ByteVector::fromShort(v5.size(), false)); + data.append(ByteVector::fromUInt16LE(v1.size())); + data.append(ByteVector::fromUInt16LE(v2.size())); + data.append(ByteVector::fromUInt16LE(v3.size())); + data.append(ByteVector::fromUInt16LE(v4.size())); + data.append(ByteVector::fromUInt16LE(v5.size())); data.append(v1); data.append(v2); data.append(v3); @@ -293,7 +284,7 @@ void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File * ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file) { data.clear(); - data.append(ByteVector::fromShort(attributeData.size(), false)); + data.append(ByteVector::fromUInt16LE(attributeData.size())); data.append(attributeData.toByteVector("")); return BaseObject::render(file); @@ -317,7 +308,7 @@ void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file) { data.clear(); - data.append(ByteVector::fromShort(attributeData.size(), false)); + data.append(ByteVector::fromUInt16LE(attributeData.size())); data.append(attributeData.toByteVector("")); return BaseObject::render(file); @@ -341,7 +332,7 @@ void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsig ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file) { data.clear(); - data.append(ByteVector::fromShort(attributeData.size(), false)); + data.append(ByteVector::fromUInt16LE(attributeData.size())); data.append(attributeData.toByteVector("")); return BaseObject::render(file); @@ -372,17 +363,17 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig file->setValid(false); break; } - BaseObject *obj; + std::shared_ptr obj; if (guid == metadataGuid) { - file->d->metadataObject = new MetadataObject(); + file->d->metadataObject.reset(new MetadataObject()); obj = file->d->metadataObject; } else if (guid == metadataLibraryGuid) { - file->d->metadataLibraryObject = new MetadataLibraryObject(); + file->d->metadataLibraryObject.reset(new MetadataLibraryObject()); obj = file->d->metadataLibraryObject; } else { - obj = new UnknownObject(guid); + obj.reset(new UnknownObject(guid)); } obj->parse(file, static_cast(size)); objects.append(obj); @@ -394,10 +385,10 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file) { data.clear(); - for (List::ConstIterator it = objects.begin(); it != objects.end(); ++it) { + for (ObjectConstIterator it = objects.begin(); it != objects.end(); ++it) { data.append((*it)->render(file)); } - data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data; + data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt32LE(data.size()) + data; return BaseObject::render(file); } @@ -416,7 +407,7 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in unsigned int pos = 16; - const int count = data.toUInt(pos, false); + const int count = data.toUInt32LE(pos); pos += 4; for (int i = 0; i < count; ++i) { @@ -424,22 +415,22 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in if (pos >= data.size()) break; - const CodecType type = static_cast(data.toUShort(pos, false)); + const CodecType type = static_cast(data.toUInt16LE(pos)); pos += 2; - int nameLength = data.toUShort(pos, false); + int nameLength = data.toUInt16LE(pos); pos += 2; const unsigned int namePos = pos; pos += nameLength * 2; - const int descLength = data.toUShort(pos, false); + const int descLength = data.toUInt16LE(pos); pos += 2; const unsigned int descPos = pos; pos += descLength * 2; - const int infoLength = data.toUShort(pos, false); + const int infoLength = data.toUInt16LE(pos); pos += 2 + infoLength * 2; if (type == CodecListObject::Audio) { @@ -489,23 +480,11 @@ ASF::File::~File() { } ASF::Tag *ASF::File::tag() const { - return d->tag; -} - -PropertyMap ASF::File::properties() const { - return d->tag->properties(); -} - -void ASF::File::removeUnsupportedProperties(const StringList &properties) { - d->tag->removeUnsupportedProperties(properties); -} - -PropertyMap ASF::File::setProperties(const PropertyMap &properties) { - return d->tag->setProperties(properties); + return d->tag.get(); } ASF::AudioProperties *ASF::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool ASF::File::save() { @@ -521,23 +500,23 @@ bool ASF::File::save() { } if (!d->contentDescriptionObject) { - d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject(); + d->contentDescriptionObject.reset(new FilePrivate::ContentDescriptionObject()); d->objects.append(d->contentDescriptionObject); } if (!d->extendedContentDescriptionObject) { - d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject(); + d->extendedContentDescriptionObject.reset(new FilePrivate::ExtendedContentDescriptionObject()); d->objects.append(d->extendedContentDescriptionObject); } if (!d->headerExtensionObject) { - d->headerExtensionObject = new FilePrivate::HeaderExtensionObject(); + d->headerExtensionObject.reset(new FilePrivate::HeaderExtensionObject()); d->objects.append(d->headerExtensionObject); } if (!d->metadataObject) { - d->metadataObject = new FilePrivate::MetadataObject(); + d->metadataObject.reset(new FilePrivate::MetadataObject()); d->headerExtensionObject->objects.append(d->metadataObject); } if (!d->metadataLibraryObject) { - d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject(); + d->metadataLibraryObject.reset(new FilePrivate::MetadataLibraryObject()); d->headerExtensionObject->objects.append(d->metadataLibraryObject); } @@ -576,16 +555,16 @@ bool ASF::File::save() { } ByteVector data; - for (List::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) { + for (FilePrivate::ObjectConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) { data.append((*it)->render(this)); } seek(16); - writeBlock(ByteVector::fromLongLong(data.size() + 30, false)); - writeBlock(ByteVector::fromUInt(d->objects.size(), false)); + writeBlock(ByteVector::fromUInt64LE(data.size() + 30)); + writeBlock(ByteVector::fromUInt32LE(d->objects.size())); writeBlock(ByteVector("\x01\x02", 2)); - insert(data, 30, static_cast(d->headerSize - 30)); + insert(data, 30, static_cast(d->headerSize - 30)); d->headerSize = data.size() + 30; @@ -608,8 +587,8 @@ void ASF::File::read() { return; } - d->tag = new ASF::Tag(); - d->properties = new ASF::AudioProperties(); + d->tag.reset(new ASF::Tag()); + d->properties.reset(new ASF::AudioProperties()); bool ok; d->headerSize = readQWORD(this, &ok); @@ -624,8 +603,8 @@ void ASF::File::read() { } seek(2, Current); - FilePrivate::FilePropertiesObject *filePropertiesObject = nullptr; - FilePrivate::StreamPropertiesObject *streamPropertiesObject = nullptr; + std::shared_ptr filePropertiesObject; + std::shared_ptr streamPropertiesObject; for (int i = 0; i < numObjects; i++) { const ByteVector guid = readBlock(16); if (guid.size() != 16) { @@ -637,29 +616,29 @@ void ASF::File::read() { setValid(false); break; } - FilePrivate::BaseObject *obj; + std::shared_ptr obj; if (guid == filePropertiesGuid) { - filePropertiesObject = new FilePrivate::FilePropertiesObject(); + filePropertiesObject.reset(new FilePrivate::FilePropertiesObject()); obj = filePropertiesObject; } else if (guid == streamPropertiesGuid) { - streamPropertiesObject = new FilePrivate::StreamPropertiesObject(); + streamPropertiesObject.reset(new FilePrivate::StreamPropertiesObject()); obj = streamPropertiesObject; } else if (guid == contentDescriptionGuid) { - d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject(); + d->contentDescriptionObject.reset(new FilePrivate::ContentDescriptionObject()); obj = d->contentDescriptionObject; } else if (guid == extendedContentDescriptionGuid) { - d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject(); + d->extendedContentDescriptionObject.reset(new FilePrivate::ExtendedContentDescriptionObject()); obj = d->extendedContentDescriptionObject; } else if (guid == headerExtensionGuid) { - d->headerExtensionObject = new FilePrivate::HeaderExtensionObject(); + d->headerExtensionObject.reset(new FilePrivate::HeaderExtensionObject()); obj = d->headerExtensionObject; } else if (guid == codecListGuid) { - obj = new FilePrivate::CodecListObject(); + obj.reset(new FilePrivate::CodecListObject()); } else { if (guid == contentEncryptionGuid || @@ -667,7 +646,7 @@ void ASF::File::read() { guid == advancedContentEncryptionGuid) { d->properties->setEncrypted(true); } - obj = new FilePrivate::UnknownObject(guid); + obj.reset(new FilePrivate::UnknownObject(guid)); } obj->parse(this, size); d->objects.append(obj); diff --git a/3rdparty/taglib/asf/asffile.h b/3rdparty/taglib/asf/asffile.h index e29984f3b..0c41924f5 100644 --- a/3rdparty/taglib/asf/asffile.h +++ b/3rdparty/taglib/asf/asffile.h @@ -70,7 +70,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns a pointer to the ASF tag of the file. @@ -82,34 +82,19 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * deleted by the user. It will be deleted when the file (object) is * destroyed. */ - virtual Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function. - */ - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - */ - PropertyMap setProperties(const PropertyMap &); + Tag *tag() const override; /*! * Returns the ASF audio properties for this file. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Returns whether or not the given \a stream can be opened as an ASF file. diff --git a/3rdparty/taglib/asf/asfpicture.cpp b/3rdparty/taglib/asf/asfpicture.cpp index 9542f9635..2dfa31c9c 100644 --- a/3rdparty/taglib/asf/asfpicture.cpp +++ b/3rdparty/taglib/asf/asfpicture.cpp @@ -23,9 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include + +#include "taglib.h" +#include "tdebug.h" #include "asfattribute.h" #include "asffile.h" @@ -34,71 +35,75 @@ using namespace Strawberry_TagLib::TagLib; -class ASF::Picture::PicturePrivate : public RefCounter { - public: +namespace { +struct PictureData { bool valid; - Type type; + ASF::Picture::Type type; String mimeType; String description; ByteVector picture; }; +} // namespace + +class ASF::Picture::PicturePrivate { + public: + explicit PicturePrivate() : data(new PictureData()) {} + + std::shared_ptr data; +}; //////////////////////////////////////////////////////////////////////////////// // Picture class members //////////////////////////////////////////////////////////////////////////////// ASF::Picture::Picture() : d(new PicturePrivate()) { - d->valid = true; + d->data->valid = true; } -ASF::Picture::Picture(const Picture& other) : d(other.d) { - d->ref(); -} +ASF::Picture::Picture(const Picture& other) : d(new PicturePrivate(*other.d)) {} ASF::Picture::~Picture() { - if (d->deref()) - delete d; + delete d; } bool ASF::Picture::isValid() const { - return d->valid; + return d->data->valid; } String ASF::Picture::mimeType() const { - return d->mimeType; + return d->data->mimeType; } void ASF::Picture::setMimeType(const String& value) { - d->mimeType = value; + d->data->mimeType = value; } ASF::Picture::Type ASF::Picture::type() const { - return d->type; + return d->data->type; } void ASF::Picture::setType(const ASF::Picture::Type &t) { - d->type = t; + d->data->type = t; } String ASF::Picture::description() const { - return d->description; + return d->data->description; } void ASF::Picture::setDescription(const String& desc) { - d->description = desc; + d->data->description = desc; } ByteVector ASF::Picture::picture() const { - return d->picture; + return d->data->picture; } void ASF::Picture::setPicture(const ByteVector &p) { - d->picture = p; + d->data->picture = p; } int ASF::Picture::dataSize() const { - return 9 + (d->mimeType.length() + d->description.length()) * 2 + - d->picture.size(); + return 9 + (d->data->mimeType.length() + d->data->description.length()) * 2 + d->data->picture.size(); } ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other) { @@ -117,51 +122,47 @@ ByteVector ASF::Picture::render() const { if (!isValid()) return ByteVector(); - return ByteVector(static_cast(d->type)) + - ByteVector::fromUInt(d->picture.size(), false) + - renderString(d->mimeType) + - renderString(d->description) + - d->picture; + return ByteVector(static_cast(d->data->type)) + ByteVector::fromUInt32LE(d->data->picture.size()) + renderString(d->data->mimeType) + renderString(d->data->description) + d->data->picture; } void ASF::Picture::parse(const ByteVector &bytes) { - d->valid = false; + d->data->valid = false; if (bytes.size() < 9) return; - int pos = 0; - d->type = static_cast(bytes[0]); + size_t pos = 0; + d->data->type = static_cast(bytes[0]); ++pos; - const unsigned int dataLen = bytes.toUInt(pos, false); + const unsigned int dataLen = bytes.toUInt32LE(pos); pos += 4; const ByteVector nullStringTerminator(2, 0); - int endPos = bytes.find(nullStringTerminator, pos, 2); - if (endPos < 0) + size_t endPos = bytes.find(nullStringTerminator, pos, 2); + if (endPos == ByteVector::npos()) return; - d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE); + d->data->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE); pos = endPos + 2; endPos = bytes.find(nullStringTerminator, pos, 2); - if (endPos < 0) + if (endPos == ByteVector::npos()) return; - d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE); + d->data->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE); pos = endPos + 2; if (dataLen + pos != bytes.size()) return; - d->picture = bytes.mid(pos, dataLen); - d->valid = true; + d->data->picture = bytes.mid(pos, dataLen); + d->data->valid = true; } ASF::Picture ASF::Picture::fromInvalid() { Picture ret; - ret.d->valid = false; + ret.d->data->valid = false; return ret; } diff --git a/3rdparty/taglib/asf/asfpicture.h b/3rdparty/taglib/asf/asfpicture.h index 5158dc09d..c22ae1791 100644 --- a/3rdparty/taglib/asf/asfpicture.h +++ b/3rdparty/taglib/asf/asfpicture.h @@ -34,6 +34,7 @@ namespace Strawberry_TagLib { namespace TagLib { namespace ASF { +class Attribute; //! An ASF attached picture interface implementation @@ -200,11 +201,11 @@ class TAGLIB_EXPORT Picture { */ int dataSize() const; -#ifndef DO_NOT_DOCUMENT - /* THIS IS PRIVATE, DON'T TOUCH IT! */ + private: + friend class Attribute; + void parse(const ByteVector&); static Picture fromInvalid(); -#endif private: class PicturePrivate; diff --git a/3rdparty/taglib/asf/asfproperties.cpp b/3rdparty/taglib/asf/asfproperties.cpp index 331c7084c..a91b46adb 100644 --- a/3rdparty/taglib/asf/asfproperties.cpp +++ b/3rdparty/taglib/asf/asfproperties.cpp @@ -23,21 +23,21 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tstring.h" #include "asfproperties.h" using namespace Strawberry_TagLib::TagLib; class ASF::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - channels(0), - bitsPerSample(0), - codec(ASF::AudioProperties::Unknown), - encrypted(false) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + bitsPerSample(0), + codec(ASF::AudioProperties::Unknown), + encrypted(false) {} int length; int bitrate; @@ -54,8 +54,7 @@ class ASF::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -ASF::AudioProperties::AudioProperties() : Strawberry_TagLib::TagLib::AudioProperties(AudioProperties::Average), - d(new AudioPropertiesPrivate()) { +ASF::AudioProperties::AudioProperties() : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { } ASF::AudioProperties::~AudioProperties() { diff --git a/3rdparty/taglib/asf/asfproperties.h b/3rdparty/taglib/asf/asfproperties.h index 38321f7bc..ab1e351b8 100644 --- a/3rdparty/taglib/asf/asfproperties.h +++ b/3rdparty/taglib/asf/asfproperties.h @@ -36,6 +36,8 @@ namespace ASF { //! An implementation of ASF audio properties class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioProperties { + friend class File; + public: /*! * Audio codec types can be used in ASF file. @@ -75,7 +77,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Destroys this ASF::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to @@ -83,29 +85,29 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -142,7 +144,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro */ bool isEncrypted() const; -#ifndef DO_NOT_DOCUMENT + private: void setLengthInMilliseconds(int value); void setBitrate(int value); void setSampleRate(int value); @@ -152,7 +154,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro void setCodecName(const String &value); void setCodecDescription(const String &value); void setEncrypted(bool value); -#endif private: class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/asf/asftag.cpp b/3rdparty/taglib/asf/asftag.cpp index 6ff370533..f007e5be1 100644 --- a/3rdparty/taglib/asf/asftag.cpp +++ b/3rdparty/taglib/asf/asftag.cpp @@ -23,7 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include +#include "tpicturemap.h" +#include "tpropertymap.h" #include "asftag.h" using namespace Strawberry_TagLib::TagLib; @@ -38,8 +39,7 @@ class ASF::Tag::TagPrivate { AttributeListMap attributeListMap; }; -ASF::Tag::Tag() : d(new TagPrivate()) { -} +ASF::Tag::Tag() : d(new TagPrivate()) {} ASF::Tag::~Tag() { delete d; @@ -104,6 +104,87 @@ String ASF::Tag::genre() const { } +PictureMap ASF::Tag::pictures() const { + + PictureMap map; + if (d->attributeListMap.contains("WM/Picture")) { + AttributeList list = d->attributeListMap["WM/Picture"]; + for (AttributeList::ConstIterator it = list.begin(); it != list.end(); ++it) { + ASF::Picture asfPicture = (*it).toPicture(); + TagLib::Picture::Type type; + switch (asfPicture.type()) { + case ASF::Picture::FileIcon: + type = TagLib::Picture::FileIcon; + break; + case ASF::Picture::OtherFileIcon: + type = TagLib::Picture::OtherFileIcon; + break; + case ASF::Picture::FrontCover: + type = TagLib::Picture::FrontCover; + break; + case ASF::Picture::BackCover: + type = TagLib::Picture::BackCover; + break; + case ASF::Picture::LeafletPage: + type = TagLib::Picture::LeafletPage; + break; + case ASF::Picture::Media: + type = TagLib::Picture::Media; + break; + case ASF::Picture::LeadArtist: + type = TagLib::Picture::LeadArtist; + break; + case ASF::Picture::Artist: + type = TagLib::Picture::Artist; + break; + case ASF::Picture::Conductor: + type = TagLib::Picture::Conductor; + break; + case ASF::Picture::Band: + type = TagLib::Picture::Band; + break; + case ASF::Picture::Composer: + type = TagLib::Picture::Composer; + break; + case ASF::Picture::Lyricist: + type = TagLib::Picture::Lyricist; + break; + case ASF::Picture::RecordingLocation: + type = TagLib::Picture::RecordingLocation; + break; + case ASF::Picture::DuringRecording: + type = TagLib::Picture::DuringRecording; + break; + case ASF::Picture::DuringPerformance: + type = TagLib::Picture::DuringPerformance; + break; + case ASF::Picture::MovieScreenCapture: + type = TagLib::Picture::MovieScreenCapture; + break; + case ASF::Picture::ColouredFish: + type = TagLib::Picture::ColouredFish; + break; + case ASF::Picture::Illustration: + type = TagLib::Picture::Illustration; + break; + case ASF::Picture::BandLogo: + type = TagLib::Picture::BandLogo; + break; + case ASF::Picture::PublisherLogo: + type = TagLib::Picture::PublisherLogo; + break; + default: + type = TagLib::Picture::Other; + break; + } + TagLib::Picture picture(asfPicture.picture(), type, asfPicture.mimeType(), asfPicture.description()); + map.insert(picture); + } + } + return PictureMap(map); + +} + void ASF::Tag::setTitle(const String &value) { d->title = value; } @@ -140,7 +221,89 @@ void ASF::Tag::setTrack(unsigned int value) { setAttribute("WM/TrackNumber", String::number(value)); } -const ASF::AttributeListMap ASF::Tag::attributeListMap() const { +void ASF::Tag::setPictures(const PictureMap &l) { + + removeItem("WM/Picture"); + for (PictureMap::ConstIterator pictureMapIt = l.begin(); pictureMapIt != l.end(); ++pictureMapIt) { + PictureList list = pictureMapIt->second; + for (PictureList::ConstIterator pictureListIt = list.begin(); pictureListIt != list.end(); ++pictureListIt) { + const TagLib::Picture picture = (*pictureListIt); + ASF::Picture asfPicture; + asfPicture.setPicture(picture.data()); + asfPicture.setMimeType(picture.mime()); + asfPicture.setDescription(picture.description()); + switch (picture.type()) { + case TagLib::Picture::Other: + asfPicture.setType(ASF::Picture::Other); + break; + case TagLib::Picture::FileIcon: + asfPicture.setType(ASF::Picture::FileIcon); + break; + case TagLib::Picture::OtherFileIcon: + asfPicture.setType(ASF::Picture::OtherFileIcon); + break; + case TagLib::Picture::FrontCover: + asfPicture.setType(ASF::Picture::FrontCover); + break; + case TagLib::Picture::BackCover: + asfPicture.setType(ASF::Picture::BackCover); + break; + case TagLib::Picture::LeafletPage: + asfPicture.setType(ASF::Picture::LeafletPage); + break; + case TagLib::Picture::Media: + asfPicture.setType(ASF::Picture::Media); + break; + case TagLib::Picture::LeadArtist: + asfPicture.setType(ASF::Picture::LeadArtist); + break; + case TagLib::Picture::Artist: + asfPicture.setType(ASF::Picture::Artist); + break; + case TagLib::Picture::Conductor: + asfPicture.setType(ASF::Picture::Conductor); + break; + case TagLib::Picture::Band: + asfPicture.setType(ASF::Picture::Band); + break; + case TagLib::Picture::Composer: + asfPicture.setType(ASF::Picture::Composer); + break; + case TagLib::Picture::Lyricist: + asfPicture.setType(ASF::Picture::Lyricist); + break; + case TagLib::Picture::RecordingLocation: + asfPicture.setType(ASF::Picture::RecordingLocation); + break; + case TagLib::Picture::DuringRecording: + asfPicture.setType(ASF::Picture::DuringRecording); + break; + case TagLib::Picture::DuringPerformance: + asfPicture.setType(ASF::Picture::DuringPerformance); + break; + case TagLib::Picture::MovieScreenCapture: + asfPicture.setType(ASF::Picture::MovieScreenCapture); + break; + case TagLib::Picture::ColouredFish: + asfPicture.setType(ASF::Picture::ColouredFish); + break; + case TagLib::Picture::Illustration: + asfPicture.setType(ASF::Picture::Illustration); + break; + case TagLib::Picture::BandLogo: + asfPicture.setType(ASF::Picture::BandLogo); + break; + case TagLib::Picture::PublisherLogo: + asfPicture.setType(ASF::Picture::PublisherLogo); + break; + } + addAttribute("WM/Picture", Attribute(asfPicture)); + } + } + +} + +const ASF::AttributeListMap &ASF::Tag::attributeListMap() const { return d->attributeListMap; } diff --git a/3rdparty/taglib/asf/asftag.h b/3rdparty/taglib/asf/asftag.h index 9552c4d06..328cf21af 100644 --- a/3rdparty/taglib/asf/asftag.h +++ b/3rdparty/taglib/asf/asftag.h @@ -47,32 +47,32 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { public: explicit Tag(); - virtual ~Tag(); + ~Tag() override; /*! * Returns the track name. */ - virtual String title() const; + String title() const override; /*! * Returns the artist name. */ - virtual String artist() const; + String artist() const override; /*! * Returns the album name; if no album name is present in the tag String::null will be returned. */ - virtual String album() const; + String album() const override; /*! * Returns the track comment. */ - virtual String comment() const; + String comment() const override; /*! * Returns the genre name; if no genre is present in the tag String::null will be returned. */ - virtual String genre() const; + String genre() const override; /*! * Returns the rating. @@ -87,32 +87,34 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { /*! * Returns the year; if there is no year set, this will return 0. */ - virtual unsigned int year() const; + unsigned int year() const override; /*! * Returns the track number; if there is no track number set, this will return 0. */ - virtual unsigned int track() const; + unsigned int track() const override; + + PictureMap pictures() const override; /*! * Sets the title to \a s. */ - virtual void setTitle(const String &value); + void setTitle(const String &value) override; /*! * Sets the artist to \a s. */ - virtual void setArtist(const String &value); + void setArtist(const String &value) override; /*! * Sets the album to \a s. If \a s is String::null then this value will be cleared. */ - virtual void setAlbum(const String &value); + void setAlbum(const String &value) override; /*! * Sets the comment to \a s. */ - virtual void setComment(const String &value); + void setComment(const String &value) override; /*! * Sets the rating to \a s. @@ -127,28 +129,30 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { /*! * Sets the genre to \a s. */ - virtual void setGenre(const String &value); + void setGenre(const String &value) override; /*! * Sets the year to \a i. If \a s is 0 then this value will be cleared. */ - virtual void setYear(unsigned int value); + void setYear(unsigned int value) override; /*! * Sets the track to \a i. If \a s is 0 then this value will be cleared. */ - virtual void setTrack(unsigned int value); + void setTrack(unsigned int value) override; + + void setPictures(const PictureMap&) override; /*! * Returns true if the tag does not contain any data. * This should be reimplemented in subclasses that provide more than the basic tagging abilities in this class. */ - virtual bool isEmpty() const; + bool isEmpty() const override; /*! * Returns a reference to the item list map. This is an AttributeListMap of all of the items in the tag. */ - const AttributeListMap attributeListMap() const; + const AttributeListMap &attributeListMap() const; /*! * \return True if a value for \a attribute is currently set. @@ -181,15 +185,17 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { */ void addAttribute(const String &name, const Attribute &attribute); - PropertyMap properties() const; - void removeUnsupportedProperties(const StringList &props); - PropertyMap setProperties(const PropertyMap &props); + PropertyMap properties() const override; + void removeUnsupportedProperties(const StringList &props) override; + PropertyMap setProperties(const PropertyMap &props) override; private: class TagPrivate; TagPrivate *d; }; + } // namespace ASF } // namespace TagLib } // namespace Strawberry_TagLib + #endif diff --git a/3rdparty/taglib/asf/asfutils.h b/3rdparty/taglib/asf/asfutils.h index 15cfab1d6..7369aed2b 100644 --- a/3rdparty/taglib/asf/asfutils.h +++ b/3rdparty/taglib/asf/asfutils.h @@ -35,39 +35,40 @@ namespace TagLib { namespace ASF { namespace { -inline unsigned short readWORD(File *file, bool *ok = 0) { +inline unsigned short readWORD(File *file, bool *ok = nullptr) { const ByteVector v = file->readBlock(2); if (v.size() != 2) { if (ok) *ok = false; return 0; } if (ok) *ok = true; - return v.toUShort(false); + return v.toUInt16LE(0); } -inline unsigned int readDWORD(File *file, bool *ok = 0) { +inline unsigned int readDWORD(File *file, bool *ok = nullptr) { const ByteVector v = file->readBlock(4); if (v.size() != 4) { if (ok) *ok = false; return 0; } if (ok) *ok = true; - return v.toUInt(false); + return v.toUInt32LE(0); } -inline long long readQWORD(File *file, bool *ok = 0) { +inline long long readQWORD(File *file, bool *ok = nullptr) { const ByteVector v = file->readBlock(8); if (v.size() != 8) { if (ok) *ok = false; return 0; } if (ok) *ok = true; - return v.toLongLong(false); + return v.toInt64LE(0); } inline String readString(File *file, int length) { + ByteVector data = file->readBlock(length); - unsigned int size = data.size(); + size_t size = data.size(); while (size >= 2) { if (data[size - 1] != '\0' || data[size - 2] != '\0') { break; @@ -78,12 +79,13 @@ inline String readString(File *file, int length) { data.resize(size); } return String(data, String::UTF16LE); + } inline ByteVector renderString(const String &str, bool includeLength = false) { - ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false); + ByteVector data = str.data(String::UTF16LE) + ByteVector::fromUInt16LE(0); if (includeLength) { - data = ByteVector::fromShort(data.size(), false) + data; + data = ByteVector::fromUInt16LE(data.size()) + data; } return data; } diff --git a/3rdparty/taglib/audioproperties.cpp b/3rdparty/taglib/audioproperties.cpp index fbae22ef3..9163dbe0a 100644 --- a/3rdparty/taglib/audioproperties.cpp +++ b/3rdparty/taglib/audioproperties.cpp @@ -50,4 +50,4 @@ String AudioProperties::toString() const { // protected methods //////////////////////////////////////////////////////////////////////////////// -AudioProperties::AudioProperties(ReadStyle) : d(nullptr) {} +AudioProperties::AudioProperties() : d(nullptr) {} diff --git a/3rdparty/taglib/audioproperties.h b/3rdparty/taglib/audioproperties.h index 95691c7f0..0db61f754 100644 --- a/3rdparty/taglib/audioproperties.h +++ b/3rdparty/taglib/audioproperties.h @@ -27,6 +27,7 @@ #define TAGLIB_AUDIOPROPERTIES_H #include "taglib_export.h" +#include "tstring.h" namespace Strawberry_TagLib { namespace TagLib { @@ -102,13 +103,11 @@ class TAGLIB_EXPORT AudioProperties { * Construct an audio properties instance. * This is protected as this class should not be instantiated directly, * but should be instantiated via its subclasses and can be fetched from the FileRef or File APIs. - * - * \see ReadStyle */ - explicit AudioProperties(ReadStyle style); + explicit AudioProperties(); private: - explicit AudioProperties(const AudioProperties&); + AudioProperties(const AudioProperties&); AudioProperties &operator=(const AudioProperties&); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/dsdiff/dsdiffdiintag.cpp b/3rdparty/taglib/dsdiff/dsdiffdiintag.cpp index 52df712b0..7943c4073 100644 --- a/3rdparty/taglib/dsdiff/dsdiffdiintag.cpp +++ b/3rdparty/taglib/dsdiff/dsdiffdiintag.cpp @@ -26,6 +26,7 @@ #include "dsdiffdiintag.h" #include "tstringlist.h" #include "tpropertymap.h" +#include "tpicturemap.h" using namespace Strawberry_TagLib::TagLib; using namespace DSDIFF::DIIN; @@ -75,21 +76,19 @@ unsigned int DSDIFF::DIIN::Tag::track() const { return 0; } +PictureMap DSDIFF::DIIN::Tag::pictures() const { + return PictureMap(); +} + void DSDIFF::DIIN::Tag::setTitle(const String &title) { - if (title.isEmpty()) - d->title = String(); - else - d->title = title; + d->title = title; } void DSDIFF::DIIN::Tag::setArtist(const String &artist) { - if (artist.isEmpty()) - d->artist = String(); - else - d->artist = artist; + d->artist = artist; } @@ -103,6 +102,8 @@ void DSDIFF::DIIN::Tag::setYear(unsigned int) {} void DSDIFF::DIIN::Tag::setTrack(unsigned int) {} +void DSDIFF::DIIN::Tag::setPictures(const PictureMap&) {} + PropertyMap DSDIFF::DIIN::Tag::properties() const { PropertyMap properties; diff --git a/3rdparty/taglib/dsdiff/dsdiffdiintag.h b/3rdparty/taglib/dsdiff/dsdiffdiintag.h index a3e614171..066f75a25 100644 --- a/3rdparty/taglib/dsdiff/dsdiffdiintag.h +++ b/3rdparty/taglib/dsdiff/dsdiffdiintag.h @@ -42,83 +42,93 @@ namespace DIIN { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { public: explicit Tag(); - virtual ~Tag(); + ~Tag() override; /*! * Returns the track name; if no track name is present in the tag String() will be returned. */ - String title() const; + String title() const override; /*! * Returns the artist name; if no artist name is present in the tag String() will be returned. */ - String artist() const; + String artist() const override; /*! * Not supported. Therefore always returns String(). */ - String album() const; + String album() const override; /*! * Not supported. Therefore always returns String(). */ - String comment() const; + String comment() const override; /*! * Not supported. Therefore always returns String(). */ - String genre() const; + String genre() const override; /*! * Not supported. Therefore always returns 0. */ - unsigned int year() const; + unsigned int year() const override; /*! * Not supported. Therefore always returns 0. */ - unsigned int track() const; + unsigned int track() const override; + + /*! + * Not supported. Therefore always returns an empty list. + */ + PictureMap pictures() const override; /*! * Sets the title to \a title. If \a title is String() then this value will be cleared. */ - void setTitle(const String &title); + void setTitle(const String &title) override; /*! * Sets the artist to \a artist. If \a artist is String() then this value will be cleared. */ - void setArtist(const String &artist); + void setArtist(const String &artist) override; /*! * Not supported and therefore ignored. */ - void setAlbum(const String &album); + void setAlbum(const String &album) override; /*! * Not supported and therefore ignored. */ - void setComment(const String &comment); + void setComment(const String &comment) override; /*! * Not supported and therefore ignored. */ - void setGenre(const String &genre); + void setGenre(const String &genre) override; /*! * Not supported and therefore ignored. */ - void setYear(unsigned int year); + void setYear(unsigned int year) override; /*! * Not supported and therefore ignored. */ - void setTrack(unsigned int track); + void setTrack(unsigned int track) override; + + /*! + * Not supported and therefore ignored. + */ + void setPictures(const PictureMap&) override; /*! * Implements the unified property interface -- export function. * Since the DIIN tag is very limited, the exported map is as well. */ - PropertyMap properties() const; + PropertyMap properties() const override; /*! * Implements the unified property interface -- import function. @@ -127,10 +137,10 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * Additionally, if the map contains tags with multiple values, * all but the first will be contained in the returned map of unsupported properties. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; private: - explicit Tag(const Tag &); + Tag(const Tag &); Tag &operator=(const Tag &); class TagPrivate; diff --git a/3rdparty/taglib/dsdiff/dsdifffile.cpp b/3rdparty/taglib/dsdiff/dsdifffile.cpp index 4c3624c98..1b6a8e1a2 100644 --- a/3rdparty/taglib/dsdiff/dsdifffile.cpp +++ b/3rdparty/taglib/dsdiff/dsdifffile.cpp @@ -23,19 +23,20 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include "tstring.h" +#include "tbytevector.h" +#include "tdebug.h" +#include "id3v2tag.h" +#include "tstringlist.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "tagunion.h" #include "dsdifffile.h" -#include - using namespace Strawberry_TagLib::TagLib; namespace { @@ -89,7 +90,6 @@ class DSDIFF::File::FilePrivate { size(0), isID3InPropChunk(false), duplicateID3V2chunkIndex(-1), - properties(nullptr), id3v2TagChunkID("ID3 "), hasID3v2(false), hasDiin(false) { @@ -97,10 +97,6 @@ class DSDIFF::File::FilePrivate { childChunkIndex[DIINIndex] = -1; } - ~FilePrivate() { - delete properties; - } - Endianness endianness; ByteVector type; unsigned long long size; @@ -118,9 +114,9 @@ class DSDIFF::File::FilePrivate { */ int duplicateID3V2chunkIndex; - AudioProperties *properties; + std::unique_ptr properties; - TagUnion tag; + DoubleTagUnion tag; ByteVector id3v2TagChunkID; @@ -211,7 +207,7 @@ PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties) { } DSDIFF::AudioProperties *DSDIFF::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool DSDIFF::File::save() { @@ -269,7 +265,10 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) { if (tags & DIIN && diinTag) { if (!diinTag->title().isEmpty()) { ByteVector diinTitle; - diinTitle.append(ByteVector::fromUInt(diinTag->title().size(), d->endianness == BigEndian)); + if (d->endianness == BigEndian) + diinTitle.append(ByteVector::fromUInt32BE(diinTag->title().size())); + else + diinTitle.append(ByteVector::fromUInt32LE(diinTag->title().size())); diinTitle.append(ByteVector::fromCString(diinTag->title().toCString())); setChildChunkData("DITI", diinTitle, DIINChunk); } @@ -278,7 +277,10 @@ bool DSDIFF::File::save(TagTypes tags, StripTags, ID3v2::Version version) { if (!diinTag->artist().isEmpty()) { ByteVector diinArtist; - diinArtist.append(ByteVector::fromUInt(diinTag->artist().size(), d->endianness == BigEndian)); + if (d->endianness == BigEndian) + diinArtist.append(ByteVector::fromUInt32BE(diinTag->artist().size())); + else + diinArtist.append(ByteVector::fromUInt32LE(diinTag->artist().size())); diinArtist.append(ByteVector::fromCString(diinTag->artist().toCString())); setChildChunkData("DIAR", diinArtist, DIINChunk); } @@ -324,7 +326,10 @@ void DSDIFF::File::removeRootChunk(unsigned int i) { unsigned long long chunkSize = d->chunks[i].size + d->chunks[i].padding + 12; d->size -= chunkSize; - insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->size), 4, 8); + else + insert(ByteVector::fromUInt64LE(d->size), 4, 8); removeBlock(d->chunks[i].offset - 12, chunkSize); @@ -357,14 +362,14 @@ void DSDIFF::File::setRootChunkData(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::fromLongLong(d->size, d->endianness == BigEndian), 4, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->size), 4, 8); + else + insert(ByteVector::fromUInt64LE(d->size), 4, 8); // Now update the specific chunk - writeChunk(d->chunks[i].name, - data, - d->chunks[i].offset - 12, - d->chunks[i].size + d->chunks[i].padding + 12); + writeChunk(d->chunks[i].name, data, d->chunks[i].offset - 12, d->chunks[i].size + d->chunks[i].padding + 12); d->chunks[i].size = data.size(); d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0; @@ -395,7 +400,10 @@ void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &da // First we update the global size d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12; - insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->size), 4, 8); + else + insert(ByteVector::fromUInt64LE(d->size), 4, 8); // Now add the chunk to the file writeChunk(name, @@ -422,14 +430,18 @@ void DSDIFF::File::removeChildChunk(unsigned int i, unsigned int childChunkNum) unsigned long long removedChunkTotalSize = childChunks[i].size + childChunks[i].padding + 12; d->size -= removedChunkTotalSize; - insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->size), 4, 8); + else + insert(ByteVector::fromUInt64LE(d->size), 4, 8); // Update child chunk size d->chunks[d->childChunkIndex[childChunkNum]].size -= removedChunkTotalSize; - insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size, - d->endianness == BigEndian), - d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->chunks[d->childChunkIndex[childChunkNum]].size), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); + else + insert(ByteVector::fromUInt64LE(d->chunks[d->childChunkIndex[childChunkNum]].size), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); // Remove the chunk removeBlock(childChunks[i].offset - 12, removedChunkTotalSize); @@ -467,19 +479,23 @@ void DSDIFF::File::setChildChunkData(unsigned int i, const ByteVector &data, uns d->size += ((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding); - insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->size), 4, 8); + else + insert(ByteVector::fromUInt64LE(d->size), 4, 8); // And the PROP chunk size d->chunks[d->childChunkIndex[childChunkNum]].size += ((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding); - insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size, d->endianness == BigEndian), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); + + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->chunks[d->childChunkIndex[childChunkNum]].size), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); + else + insert(ByteVector::fromUInt64LE(d->chunks[d->childChunkIndex[childChunkNum]].size), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); // Now update the specific chunk - writeChunk(childChunks[i].name, - data, - childChunks[i].offset - 12, - childChunks[i].size + childChunks[i].padding + 12); + writeChunk(childChunks[i].name, data, childChunks[i].offset - 12, childChunks[i].size + childChunks[i].padding + 12); childChunks[i].size = data.size(); childChunks[i].padding = (data.size() & 0x01) ? 1 : 0; @@ -523,14 +539,18 @@ void DSDIFF::File::setChildChunkData(const ByteVector &name, const ByteVector &d // First we update the global size d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12; - insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->size), 4, 8); + else + insert(ByteVector::fromUInt64LE(d->size), 4, 8); // And the child chunk size d->chunks[d->childChunkIndex[childChunkNum]].size += (offset & 1) + ((data.size() + 1) & ~1) + 12; - insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size, - d->endianness == BigEndian), - d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); + if (d->endianness == BigEndian) + insert(ByteVector::fromUInt64BE(d->chunks[d->childChunkIndex[childChunkNum]].size), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); + else + insert(ByteVector::fromUInt64LE(d->chunks[d->childChunkIndex[childChunkNum]].size), d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8); // Now add the chunk to the file @@ -587,14 +607,14 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti bool bigEndian = (d->endianness == BigEndian); d->type = readBlock(4); - d->size = readBlock(8).toLongLong(bigEndian); + d->size = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0); d->format = readBlock(4); // + 12: chunk header at least, fix for additional junk bytes while (tell() + 12 <= length()) { ByteVector chunkName = readBlock(4); - unsigned long long chunkSize = readBlock(8).toLongLong(bigEndian); + unsigned long long chunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0); if (!isValidChunkID(chunkName)) { debug("DSDIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID"); @@ -654,7 +674,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti while (tell() + 12 <= dstChunkEnd) { ByteVector dstChunkName = readBlock(4); - long long dstChunkSize = readBlock(8).toLongLong(bigEndian); + long long dstChunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0); if (!isValidChunkID(dstChunkName)) { debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName + "' has invalid ID"); @@ -670,8 +690,8 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti if (dstChunkName == "FRTE") { // Found the DST frame information chunk - dstNumFrames = readBlock(4).toUInt(bigEndian); - dstFrameRate = readBlock(2).toUShort(bigEndian); + dstNumFrames = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0); + dstFrameRate = bigEndian ? readBlock(2).toUInt16BE(0) : readBlock(2).toUInt16LE(0); // Found the wanted one, no need to look at the others break; } @@ -696,7 +716,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti seek(d->chunks[i].offset + 4); while (tell() + 12 <= propChunkEnd) { ByteVector propChunkName = readBlock(4); - long long propChunkSize = readBlock(8).toLongLong(bigEndian); + long long propChunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0); if (!isValidChunkID(propChunkName)) { debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName + "' has invalid ID"); @@ -742,7 +762,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti while (tell() + 12 <= diinChunkEnd) { ByteVector diinChunkName = readBlock(4); - long long diinChunkSize = readBlock(8).toLongLong(bigEndian); + long long diinChunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0); if (!isValidChunkID(diinChunkName)) { debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName + "' has invalid ID"); @@ -802,8 +822,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti unsigned short channels = 0; for (unsigned int i = 0; i < d->childChunks[PROPChunk].size(); i++) { - if (d->childChunks[PROPChunk][i].name == "ID3 " || - d->childChunks[PROPChunk][i].name == "id3 ") { + if (d->childChunks[PROPChunk][i].name == "ID3 " || d->childChunks[PROPChunk][i].name == "id3 ") { if (d->hasID3v2) { d->duplicateID3V2chunkIndex = i; // ID3V2 tag has already been found at root level @@ -817,12 +836,12 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti else if (d->childChunks[PROPChunk][i].name == "FS ") { // Sample rate seek(d->childChunks[PROPChunk][i].offset); - sampleRate = readBlock(4).toUInt(0, 4, bigEndian); + sampleRate = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0); } else if (d->childChunks[PROPChunk][i].name == "CHNL") { // Channels seek(d->childChunks[PROPChunk][i].offset); - channels = readBlock(2).toShort(0, bigEndian); + channels = bigEndian ? readBlock(2).toInt16BE(0) : readBlock(2).toInt16LE(0); } } @@ -834,7 +853,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti for (unsigned int i = 0; i < d->childChunks[DIINChunk].size(); i++) { if (d->childChunks[DIINChunk][i].name == "DITI") { seek(d->childChunks[DIINChunk][i].offset); - unsigned int titleStrLength = readBlock(4).toUInt(0, 4, bigEndian); + unsigned int titleStrLength = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0); if (titleStrLength <= d->childChunks[DIINChunk][i].size) { ByteVector titleStr = readBlock(titleStrLength); d->tag.access(DIINIndex, false)->setTitle(titleStr); @@ -842,7 +861,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti } else if (d->childChunks[DIINChunk][i].name == "DIAR") { seek(d->childChunks[DIINChunk][i].offset); - unsigned int artistStrLength = readBlock(4).toUInt(0, 4, bigEndian); + unsigned int artistStrLength = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0); if (artistStrLength <= d->childChunks[DIINChunk][i].size) { ByteVector artistStr = readBlock(artistStrLength); d->tag.access(DIINIndex, false)->setArtist(artistStr); @@ -868,7 +887,7 @@ void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle properti if (lengthDSDSamplesTimeChannels > 0) bitrate = (audioDataSizeinBytes * 8 * sampleRate) / lengthDSDSamplesTimeChannels / 1000; - d->properties = new AudioProperties(sampleRate, channels, lengthDSDSamplesTimeChannels, bitrate, propertiesStyle); + d->properties.reset(new AudioProperties(sampleRate, channels, lengthDSDSamplesTimeChannels, bitrate, propertiesStyle)); } if (!ID3v2Tag()) { @@ -887,7 +906,10 @@ void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, un combined.append(ByteVector(leadingPadding, '\x00')); combined.append(name); - combined.append(ByteVector::fromLongLong(data.size(), d->endianness == BigEndian)); + if (d->endianness == BigEndian) + combined.append(ByteVector::fromUInt64BE(data.size())); + else + combined.append(ByteVector::fromUInt64LE(data.size())); combined.append(data); if ((data.size() & 0x01) != 0) combined.append('\x00'); diff --git a/3rdparty/taglib/dsdiff/dsdifffile.h b/3rdparty/taglib/dsdiff/dsdifffile.h index d638e5cd2..c1a5bf002 100644 --- a/3rdparty/taglib/dsdiff/dsdifffile.h +++ b/3rdparty/taglib/dsdiff/dsdifffile.h @@ -95,7 +95,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns a pointer to a tag that is the union of the ID3v2 and DIIN tags. @@ -110,7 +110,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \see ID3v2Tag() * \see DIINTag() */ - virtual Tag *tag() const; + Tag *tag() const override; /*! * Returns the ID3V2 Tag for this file. @@ -132,21 +132,21 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * Implements the unified property interface -- export function. * This method forwards to ID3v2::Tag::properties(). */ - PropertyMap properties() const; + PropertyMap properties() const override; - void removeUnsupportedProperties(const StringList &properties); + void removeUnsupportedProperties(const StringList &properties) override; /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). */ - PropertyMap setProperties(const PropertyMap &properties); + PropertyMap setProperties(const PropertyMap &properties) override; /*! * Returns the AIFF::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. If at least one tag -- ID3v1 or DIIN -- exists this will duplicate its content into the other tag. @@ -161,7 +161,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * * \see save(int tags) */ - virtual bool save(); + bool save() override; /*! * Save the file. If \a strip is specified, @@ -209,7 +209,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { File(IOStream *stream, Endianness endianness); private: - explicit File(const File &); + File(const File &); File &operator=(const File &); void removeRootChunk(const ByteVector &id); diff --git a/3rdparty/taglib/dsdiff/dsdiffproperties.cpp b/3rdparty/taglib/dsdiff/dsdiffproperties.cpp index 545e60f00..90409730e 100644 --- a/3rdparty/taglib/dsdiff/dsdiffproperties.cpp +++ b/3rdparty/taglib/dsdiff/dsdiffproperties.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "dsdiffproperties.h" @@ -32,12 +32,12 @@ using namespace Strawberry_TagLib::TagLib; class DSDIFF::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - channels(0), - sampleWidth(0), - sampleCount(0) { + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + sampleWidth(0), + sampleCount(0) { } int length; @@ -52,9 +52,7 @@ class DSDIFF::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -DSDIFF::AudioProperties::AudioProperties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style) { - - d = new AudioPropertiesPrivate; +DSDIFF::AudioProperties::AudioProperties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate) { d->channels = channels; d->sampleCount = samplesCount; diff --git a/3rdparty/taglib/dsdiff/dsdiffproperties.h b/3rdparty/taglib/dsdiff/dsdiffproperties.h index cd079857d..48c762017 100644 --- a/3rdparty/taglib/dsdiff/dsdiffproperties.h +++ b/3rdparty/taglib/dsdiff/dsdiffproperties.h @@ -45,26 +45,26 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of DSDIFF::AudioProperties with the data read from the ByteVector \a data. */ - explicit AudioProperties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle style); + explicit AudioProperties(const unsigned int sampleRate, const unsigned short channels, const unsigned long long samplesCount, const int bitrate, ReadStyle); /*! * Destroys this DSDIFF::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; // Reimplementations. - virtual int lengthInSeconds() const; - virtual int lengthInMilliseconds() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; + int lengthInSeconds() const override; + int lengthInMilliseconds() const override; + int bitrate() const override; + int sampleRate() const override; + int channels() const override; int bitsPerSample() const; long long sampleCount() const; private: - explicit AudioProperties(const AudioProperties &); + AudioProperties(const AudioProperties &); AudioProperties &operator=(const AudioProperties &); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/dsf/dsffile.cpp b/3rdparty/taglib/dsf/dsffile.cpp index ad2fda1e8..82c3ea538 100644 --- a/3rdparty/taglib/dsf/dsffile.cpp +++ b/3rdparty/taglib/dsf/dsffile.cpp @@ -23,12 +23,14 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include +#include + +#include "tbytevector.h" +#include "tdebug.h" +#include "id3v2tag.h" +#include "tstringlist.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "dsffile.h" @@ -39,20 +41,13 @@ using namespace Strawberry_TagLib::TagLib; class DSF::File::FilePrivate { public: FilePrivate() : fileSize(0), - metadataOffset(0), - properties(nullptr), - tag(nullptr) { - } - - ~FilePrivate() { - delete properties; - delete tag; - } + metadataOffset(0) {} long long fileSize; long long metadataOffset; - AudioProperties *properties; - ID3v2::Tag *tag; + + std::unique_ptr properties; + std::unique_ptr tag; }; //////////////////////////////////////////////////////////////////////////////// @@ -91,7 +86,11 @@ DSF::File::~File() { } ID3v2::Tag *DSF::File::tag() const { - return d->tag; + return d->tag.get(); +} + +DSF::AudioProperties *DSF::File::audioProperties() const { + return d->properties.get(); } PropertyMap DSF::File::properties() const { @@ -102,10 +101,6 @@ PropertyMap DSF::File::setProperties(const PropertyMap &properties) { return d->tag->setProperties(properties); } -DSF::AudioProperties *DSF::File::audioProperties() const { - return d->properties; -} - bool DSF::File::save() { if (readOnly()) { @@ -125,13 +120,13 @@ bool DSF::File::save() { // Update the file size if (d->fileSize != newFileSize) { - insert(ByteVector::fromLongLong(newFileSize, false), 12, 8); + insert(ByteVector::fromUInt64LE(newFileSize), 12, 8); d->fileSize = newFileSize; } // Update the metadata offset to 0 since there is no longer a tag if (d->metadataOffset) { - insert(ByteVector::fromLongLong(0ULL, false), 20, 8); + insert(ByteVector::fromUInt64LE(0ULL), 20, 8); d->metadataOffset = 0; } @@ -147,13 +142,13 @@ bool DSF::File::save() { // Update the file size if (d->fileSize != newFileSize) { - insert(ByteVector::fromLongLong(newFileSize, false), 12, 8); + insert(ByteVector::fromUInt64LE(newFileSize), 12, 8); d->fileSize = newFileSize; } // Update the metadata offset if (d->metadataOffset != newMetadataOffset) { - insert(ByteVector::fromLongLong(newMetadataOffset, false), 20, 8); + insert(ByteVector::fromUInt64LE(newMetadataOffset), 20, 8); d->metadataOffset = newMetadataOffset; } @@ -183,7 +178,7 @@ void DSF::File::read(bool, AudioProperties::ReadStyle propertiesStyle) { return; } - long long chunkSize = readBlock(8).toLongLong(false); + long long chunkSize = readBlock(8).toInt64LE(0); // Integrity check if (28 != chunkSize) { @@ -192,7 +187,7 @@ void DSF::File::read(bool, AudioProperties::ReadStyle propertiesStyle) { return; } - d->fileSize = readBlock(8).toLongLong(false); + d->fileSize = readBlock(8).toInt64LE(0); // File is malformed or corrupted if (d->fileSize != length()) { @@ -201,7 +196,7 @@ void DSF::File::read(bool, AudioProperties::ReadStyle propertiesStyle) { return; } - d->metadataOffset = readBlock(8).toLongLong(false); + d->metadataOffset = readBlock(8).toInt64LE(0); // File is malformed or corrupted if (d->metadataOffset > d->fileSize) { @@ -218,16 +213,16 @@ void DSF::File::read(bool, AudioProperties::ReadStyle propertiesStyle) { return; } - chunkSize = readBlock(8).toLongLong(false); + chunkSize = readBlock(8).toInt64LE(0); - d->properties = new AudioProperties(readBlock(chunkSize), propertiesStyle); + d->properties.reset(new AudioProperties(readBlock(chunkSize), propertiesStyle)); // Skip the data chunk // A metadata offset of 0 indicates the absence of an ID3v2 tag if (0 == d->metadataOffset) - d->tag = new ID3v2::Tag(); + d->tag.reset(new ID3v2::Tag()); else - d->tag = new ID3v2::Tag(this, d->metadataOffset); + d->tag.reset(new ID3v2::Tag(this, d->metadataOffset)); } diff --git a/3rdparty/taglib/dsf/dsffile.h b/3rdparty/taglib/dsf/dsffile.h index 9c777c0f8..129b4fdb7 100644 --- a/3rdparty/taglib/dsf/dsffile.h +++ b/3rdparty/taglib/dsf/dsffile.h @@ -71,35 +71,35 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. */ - ID3v2::Tag *tag() const; + ID3v2::Tag *tag() const override; /*! * Implements the unified property interface -- export function. * This method forwards to ID3v2::Tag::properties(). */ - PropertyMap properties() const; + PropertyMap properties() const override; /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; /*! * Returns the DSF::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Saves the file. */ - virtual bool save(); + bool save() override; /*! * Returns whether or not the given \a stream can be opened as a DSF file. @@ -110,7 +110,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File &); + File(const File &); File &operator=(const File &); void read(bool readProperties, AudioProperties::ReadStyle propertiesStyle); diff --git a/3rdparty/taglib/dsf/dsfproperties.cpp b/3rdparty/taglib/dsf/dsfproperties.cpp index 689d20ab8..a8e9f5ebd 100644 --- a/3rdparty/taglib/dsf/dsfproperties.cpp +++ b/3rdparty/taglib/dsf/dsfproperties.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "dsfproperties.h" @@ -32,16 +32,16 @@ using namespace Strawberry_TagLib::TagLib; class DSF::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : formatVersion(0), - formatID(0), - channelType(0), - channelNum(0), - samplingFrequency(0), - bitsPerSample(0), - sampleCount(0), - blockSizePerChannel(0), - bitrate(0), - length(0) { + explicit AudioPropertiesPrivate() : formatVersion(0), + formatID(0), + channelType(0), + channelNum(0), + samplingFrequency(0), + bitsPerSample(0), + sampleCount(0), + blockSizePerChannel(0), + bitrate(0), + length(0) { } // Nomenclature is from DSF file format specification @@ -55,16 +55,15 @@ class DSF::AudioProperties::AudioPropertiesPrivate { unsigned int blockSizePerChannel; // Computed - unsigned int bitrate; - unsigned int length; + int bitrate; + int length; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -DSF::AudioProperties::AudioProperties(const ByteVector &data, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style) { - d = new AudioPropertiesPrivate; +DSF::AudioProperties::AudioProperties(const ByteVector &data, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(data); } @@ -122,15 +121,15 @@ int DSF::AudioProperties::blockSizePerChannel() const { //////////////////////////////////////////////////////////////////////////////// void DSF::AudioProperties::read(const ByteVector &data) { - d->formatVersion = data.toUInt(0U, false); - d->formatID = data.toUInt(4U, false); - d->channelType = data.toUInt(8U, false); - d->channelNum = data.toUInt(12U, false); - d->samplingFrequency = data.toUInt(16U, false); - d->bitsPerSample = data.toUInt(20U, false); - d->sampleCount = data.toLongLong(24U, false); - d->blockSizePerChannel = data.toUInt(32U, false); + d->formatVersion = data.toUInt32LE(0); + d->formatID = data.toUInt32LE(4); + d->channelType = data.toUInt32LE(8); + d->channelNum = data.toUInt32LE(12); + d->samplingFrequency = data.toUInt32LE(16); + d->bitsPerSample = data.toUInt32LE(20); + d->sampleCount = data.toInt64LE(24); + d->blockSizePerChannel = data.toUInt32LE(32); - d->bitrate = static_cast((d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0 + 0.5); - d->length = d->samplingFrequency > 0 ? static_cast(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5) : 0; + d->bitrate = static_cast((d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0 + 0.5); + d->length = d->samplingFrequency > 0 ? static_cast(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5) : 0; } diff --git a/3rdparty/taglib/dsf/dsfproperties.h b/3rdparty/taglib/dsf/dsfproperties.h index 0bcb998ec..b23c78c23 100644 --- a/3rdparty/taglib/dsf/dsfproperties.h +++ b/3rdparty/taglib/dsf/dsfproperties.h @@ -45,20 +45,20 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of DSF::AudioProperties with the data read from the ByteVector \a data. */ - explicit AudioProperties(const ByteVector &data, ReadStyle style); + explicit AudioProperties(const ByteVector &data, ReadStyle); /*! * Destroys this DSF::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; // Reimplementations. - virtual int lengthInSeconds() const; - virtual int lengthInMilliseconds() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; + int lengthInSeconds() const override; + int lengthInMilliseconds() const override; + int bitrate() const override; + int sampleRate() const override; + int channels() const override; int formatVersion() const; int formatID() const; @@ -79,7 +79,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int blockSizePerChannel() const; private: - explicit AudioProperties(const AudioProperties&); + AudioProperties(const AudioProperties&); AudioProperties &operator=(const AudioProperties&); void read(const ByteVector &data); diff --git a/3rdparty/taglib/fileref.cpp b/3rdparty/taglib/fileref.cpp index 4abed154b..507209db0 100644 --- a/3rdparty/taglib/fileref.cpp +++ b/3rdparty/taglib/fileref.cpp @@ -27,11 +27,12 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include + #include #include #include #include -#include #include "fileref.h" #include "asffile.h" @@ -58,7 +59,7 @@ using namespace Strawberry_TagLib::TagLib; namespace { -typedef List ResolverList; +typedef List ResolverList; ResolverList fileTypeResolvers; // Detect the file type by user-defined resolvers. @@ -81,14 +82,14 @@ File *detectByResolvers(FileName fileName, bool readAudioProperties, AudioProper File *detectByExtension(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { #ifdef _WIN32 - const String s = stream->name().toString(); + const String s(stream->name().wstr()); #else const String s(stream->name()); #endif String ext; - const int pos = s.rfind("."); - if (pos != -1) + const size_t pos = s.rfind("."); + if (pos != String::npos()) ext = s.substr(pos + 1).upper(); // If this list is updated, the method defaultFileExtensions() should also be @@ -105,7 +106,7 @@ File *detectByExtension(IOStream *stream, bool readAudioProperties, AudioPropert if (ext == "OGG") return new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle); if (ext == "FLAC") - return new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + return new FLAC::File(stream, readAudioProperties, audioPropertiesStyle); if (ext == "MPC") return new MPC::File(stream, readAudioProperties, audioPropertiesStyle); if (ext == "WV") @@ -157,7 +158,7 @@ File *detectByContent(IOStream *stream, bool readAudioProperties, AudioPropertie else if (Ogg::FLAC::File::isSupported(stream)) file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle); else if (FLAC::File::isSupported(stream)) - file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + file = new FLAC::File(stream, readAudioProperties, audioPropertiesStyle); else if (MPC::File::isSupported(stream)) file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle); else if (WavPack::File::isSupported(stream)) @@ -196,87 +197,10 @@ File *detectByContent(IOStream *stream, bool readAudioProperties, AudioPropertie } -// Internal function that supports FileRef::create(). -// This looks redundant, but necessary in order not to change the previous -// behavior of FileRef::create(). +struct FileRefData { + FileRefData() : file(nullptr), stream(nullptr) {} -File *createInternal(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { - - File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); - if (file) return file; - -#ifdef _WIN32 - const String s = fileName.toString(); -#else - const String s(fileName); -#endif - - String ext; - const int pos = s.rfind("."); - if (pos != -1) - ext = s.substr(pos + 1).upper(); - - if (ext.isEmpty()) - return nullptr; - - if (ext == "MP3") - return new MPEG::File(fileName, ID3v2::FrameFactory::instance(), 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_flac = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if (file_flac->isValid()) - return file_flac; - delete file_flac; - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - } - if (ext == "FLAC") - return new FLAC::File(fileName, ID3v2::FrameFactory::instance(), 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" || ext == "M4V") - 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); - if (ext == "DFF" || ext == "DSDIFF") - return new DSDIFF::File(fileName, readAudioProperties, audioPropertiesStyle); - if (ext == "DSF") - return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle); - - return nullptr; - -} -} // namespace - -class FileRef::FileRefPrivate : public RefCounter { - public: - FileRefPrivate() : file(nullptr), stream(nullptr) {} - - ~FileRefPrivate() override { + ~FileRefData() { delete file; delete stream; } @@ -285,6 +209,15 @@ class FileRef::FileRefPrivate : public RefCounter { IOStream *stream; }; +} // namespace + +class FileRef::FileRefPrivate { + public: + FileRefPrivate() : data(new FileRefData()) {} + + std::shared_ptr data; +}; + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -300,18 +233,13 @@ FileRef::FileRef(IOStream *stream, bool readAudioProperties, AudioProperties::Re } FileRef::FileRef(File *file) : d(new FileRefPrivate()) { - d->file = file; + d->data->file = file; } -FileRef::FileRef(const FileRef &ref) : d(ref.d) { - d->ref(); -} +FileRef::FileRef(const FileRef &ref) : d(new FileRefPrivate(*ref.d)) {} FileRef::~FileRef() { - - if (d->deref()) - delete d; - + delete d; } Tag *FileRef::tag() const { @@ -320,22 +248,50 @@ Tag *FileRef::tag() const { debug("FileRef::tag() - Called without a valid file."); return nullptr; } - return d->file->tag(); + return d->data->file->tag(); } +PropertyMap FileRef::properties() const { + if (isNull()) { + debug("FileRef::properties() - Called without a valid file."); + return PropertyMap(); + } + + return d->data->file->properties(); +} + +void FileRef::removeUnsupportedProperties(const StringList &properties) { + if (isNull()) { + debug("FileRef::removeUnsupportedProperties() - Called without a valid file."); + return; + } + + d->data->file->removeUnsupportedProperties(properties); +} + + +PropertyMap FileRef::setProperties(const PropertyMap &properties) { + if (isNull()) { + debug("FileRef::setProperties() - Called without a valid file."); + return PropertyMap(); + } + + return d->data->file->setProperties(properties); +} + AudioProperties *FileRef::audioProperties() const { if (isNull()) { debug("FileRef::audioProperties() - Called without a valid file."); return nullptr; } - return d->file->audioProperties(); + return d->data->file->audioProperties(); } File *FileRef::file() const { - return d->file; + return d->data->file; } bool FileRef::save() { @@ -344,7 +300,7 @@ bool FileRef::save() { debug("FileRef::save() - Called without a valid file."); return false; } - return d->file->save(); + return d->data->file->save(); } @@ -393,8 +349,12 @@ StringList FileRef::defaultFileExtensions() { } +bool FileRef::isValid() const { + return (d->data->file && d->data->file->isValid()); +} + bool FileRef::isNull() const { - return (!d->file || !d->file->isValid()); + return (!d->data->file || !d->data->file->isValid()); } FileRef &FileRef::operator=(const FileRef &ref) { @@ -409,15 +369,11 @@ void FileRef::swap(FileRef &ref) { } bool FileRef::operator==(const FileRef &ref) const { - return (ref.d->file == d->file); + return (ref.d->data == d->data); } bool FileRef::operator!=(const FileRef &ref) const { - return (ref.d->file != d->file); -} - -File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { // static - return createInternal(fileName, readAudioProperties, audioPropertiesStyle); + return (ref.d->data != d->data); } //////////////////////////////////////////////////////////////////////////////// @@ -428,28 +384,27 @@ void FileRef::parse(FileName fileName, bool readAudioProperties, AudioProperties // Try user-defined resolvers. - d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); - if (d->file) + d->data->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); + if (d->data->file) return; // Try to resolve file types based on the file extension. - d->stream = new FileStream(fileName); - d->file = detectByExtension(d->stream, readAudioProperties, audioPropertiesStyle); - if (d->file) + d->data->stream = new FileStream(fileName); + d->data->file = detectByExtension(d->data->stream, readAudioProperties, audioPropertiesStyle); + if (d->data->file) return; // At last, try to resolve file types based on the actual content. - d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle); - if (d->file) + d->data->file = detectByContent(d->data->stream, readAudioProperties, audioPropertiesStyle); + if (d->data->file) return; // Stream have to be closed here if failed to resolve file types. - delete d->stream; - d->stream = nullptr; - + delete d->data->stream; + d->data->stream = nullptr; } void FileRef::parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { @@ -458,12 +413,12 @@ void FileRef::parse(IOStream *stream, bool readAudioProperties, AudioProperties: // Try to resolve file types based on the file extension. - d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle); - if (d->file) + d->data->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle); + if (d->data->file) return; // At last, try to resolve file types based on the actual content of the file. - d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle); + d->data->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle); } diff --git a/3rdparty/taglib/fileref.h b/3rdparty/taglib/fileref.h index a7e026462..47be18cf5 100644 --- a/3rdparty/taglib/fileref.h +++ b/3rdparty/taglib/fileref.h @@ -30,6 +30,7 @@ #include "tstringlist.h" #include "taglib_export.h" +#include "tpropertymap.h" #include "audioproperties.h" namespace Strawberry_TagLib { @@ -85,7 +86,7 @@ class TAGLIB_EXPORT FileRef { class TAGLIB_EXPORT FileTypeResolver { public: - virtual ~FileTypeResolver(); + virtual ~FileTypeResolver() {} /*! * This method must be overridden to provide an additional file type resolver. * If the resolver is able to determine the file type it should return a valid File object; if not it should return 0. @@ -151,6 +152,34 @@ class TAGLIB_EXPORT FileRef { */ Tag *tag() const; + /*! + * Exports the tags of the file as dictionary mapping (human readable) tag names (uppercase Strings) to StringLists of tag values. + * Calls the according specialization in the File subclasses. + * For each metadata object of the file that could not be parsed into the PropertyMap format, + * the returend map's unsupportedData() list will contain one entry identifying that object (e.g. the frame type for ID3v2 tags). + * Use removeUnsupportedProperties() to remove (a subset of) them. + * For files that contain more than one tag (e.g. an MP3 with both an ID3v1 and an ID3v2 tag) only the most "modern" one will be exported (ID3v2 in this case). + */ + PropertyMap properties() const; + + /*! + * Removes unsupported properties, or a subset of them, from the file's metadata. + * The parameter \a properties must contain only entries from properties().unsupportedData(). + */ + void removeUnsupportedProperties(const StringList &properties); + + /*! + * Sets the tags of this File to those specified in \a properties. + * Calls the according specialization method in the subclasses of File to do the translation into the format-specific details. + * If some value(s) could not be written imported to the specific metadata format, + * the returned PropertyMap will contain those value(s). Otherwise it will be empty, indicating that no problems occured. + * With file types that support several tag formats (for instance, MP3 files can have ID3v1, ID3v2, and APEv2 tags), + * this function will create the most appropriate one (ID3v2 for MP3 files). Older formats will be updated as well, + * if they exist, but won't be taken into account for the return value of this function. + * See the documentation of the subclass implementations for detailed descriptions. + */ + PropertyMap setProperties(const PropertyMap &properties); + /*! * Returns the audio properties for this FileRef. * If no audio properties were read then this will returns a null pointer. @@ -208,6 +237,13 @@ class TAGLIB_EXPORT FileRef { */ static StringList defaultFileExtensions(); + /*! + * Returns true if the file is open and readable. + * + * \note Just a negative of isNull(). + */ + bool isValid() const; + /*! * Returns true if the file (and as such other pointers) are null. */ @@ -233,17 +269,6 @@ class TAGLIB_EXPORT FileRef { */ bool operator!=(const FileRef &ref) const; - /*! - * A simple implementation of file type guessing. - * If \a readAudioProperties is true then the audio properties will be read using \a audioPropertiesStyle. - * If \a readAudioProperties is false then \a audioPropertiesStyle will be ignored. - * - * \note You generally shouldn't use this method, but instead the constructor directly. - * - * \deprecated - */ - static File *create(FileName fileName, bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); - private: void parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle); void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle); diff --git a/3rdparty/taglib/flac/flacfile.cpp b/3rdparty/taglib/flac/flacfile.cpp index a7d19c2d2..6c419416e 100644 --- a/3rdparty/taglib/flac/flacfile.cpp +++ b/3rdparty/taglib/flac/flacfile.cpp @@ -23,18 +23,20 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include -#include -#include +#include "tbytevector.h" +#include "tstring.h" +#include "tlist.h" +#include "tdebug.h" +#include "tagunion.h" +#include "tpropertymap.h" +#include "tagutils.h" + +#include "id3v2header.h" +#include "id3v2tag.h" +#include "id3v1tag.h" +#include "xiphcomment.h" #include "flacpicture.h" #include "flacfile.h" @@ -44,7 +46,7 @@ using namespace Strawberry_TagLib::TagLib; namespace { -typedef List BlockList; +typedef List> BlockList; typedef BlockList::Iterator BlockIterator; typedef BlockList::Iterator BlockConstIterator; @@ -52,43 +54,54 @@ enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 }; -const long MinPaddingLength = 4096; -const long MaxPaddingLegnth = 1024 * 1024; +const long long MinPaddingLength = 4096; +const long long MaxPaddingLegnth = 1024 * 1024; const char LastBlockFlag = '\x80'; } // namespace +namespace Strawberry_TagLib { +namespace TagLib { +namespace FLAC { +// Enables BlockList::find() to take raw pointers. + +bool operator==(std::shared_ptr lhs, MetadataBlock *rhs); +bool operator==(std::shared_ptr lhs, MetadataBlock *rhs) { + return lhs.get() == rhs; +} +} // namespace FLAC +} // namespace TagLib +} // namespace Strawberry_TagLib + class FLAC::File::FilePrivate { public: - explicit FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : ID3v2FrameFactory(frameFactory), - ID3v2Location(-1), - ID3v2OriginalSize(0), - ID3v1Location(-1), - properties(nullptr), - flacStart(0), - streamStart(0), - scanned(false) { - blocks.setAutoDelete(true); - } + explicit FilePrivate(const ID3v2::FrameFactory *frameFactory) : ID3v2FrameFactory(ID3v2::FrameFactory::instance()), + ID3v2Location(-1), + ID3v2OriginalSize(0), + ID3v1Location(-1), + flacStart(0), + streamStart(0), + scanned(false) { + + if (frameFactory) + ID3v2FrameFactory = frameFactory; - ~FilePrivate() { - delete properties; } const ID3v2::FrameFactory *ID3v2FrameFactory; - long ID3v2Location; - long ID3v2OriginalSize; + long long ID3v2Location; + long long ID3v2OriginalSize; - long ID3v1Location; + long long ID3v1Location; - TagUnion tag; + TripleTagUnion tag; - AudioProperties *properties; + std::unique_ptr properties; ByteVector xiphCommentData; BlockList blocks; - long flacStart; - long streamStart; + long long flacStart; + long long streamStart; bool scanned; }; @@ -101,7 +114,7 @@ bool FLAC::File::isSupported(IOStream *stream) { // A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede. const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); - return (buffer.find("fLaC") >= 0); + return (buffer.find("fLaC") != ByteVector::npos()); } @@ -109,14 +122,14 @@ bool FLAC::File::isSupported(IOStream *stream) { // public members //////////////////////////////////////////////////////////////////////////////// -FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(frameFactory)) { +FLAC::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle, ID3v2::FrameFactory *frameFactory) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(frameFactory)) { if (isOpen()) read(readProperties); } -FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate(frameFactory)) { +FLAC::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle, ID3v2::FrameFactory *frameFactory) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate(frameFactory)) { if (isOpen()) read(readProperties); @@ -131,20 +144,12 @@ Strawberry_TagLib::TagLib::Tag *FLAC::File::tag() const { return &d->tag; } -PropertyMap FLAC::File::properties() const { - return d->tag.properties(); -} - -void FLAC::File::removeUnsupportedProperties(const StringList &unsupported) { - d->tag.removeUnsupportedProperties(unsupported); -} - PropertyMap FLAC::File::setProperties(const PropertyMap &properties) { return xiphComment(true)->setProperties(properties); } FLAC::AudioProperties *FLAC::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool FLAC::File::save() { @@ -170,20 +175,19 @@ bool FLAC::File::save() { for (BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { if ((*it)->code() == MetadataBlock::VorbisComment) { // Set the new Vorbis Comment block - delete *it; d->blocks.erase(it); break; } } - d->blocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)); + d->blocks.append(std::shared_ptr(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData))); // Render data for the metadata blocks ByteVector data; for (BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { ByteVector blockData = (*it)->render(); - ByteVector blockHeader = ByteVector::fromUInt(blockData.size()); + ByteVector blockHeader = ByteVector::fromUInt32BE(blockData.size()); blockHeader[0] = (*it)->code(); data.append(blockHeader); data.append(blockData); @@ -191,8 +195,8 @@ bool FLAC::File::save() { // Compute the amount of padding, and append that to data. - long originalLength = d->streamStart - d->flacStart; - long paddingLength = originalLength - data.size() - 4; + long long originalLength = d->streamStart - d->flacStart; + long long paddingLength = originalLength - data.size() - 4; if (paddingLength <= 0) { paddingLength = MinPaddingLength; @@ -200,7 +204,7 @@ bool FLAC::File::save() { else { // Padding won't increase beyond 1% of the file size or 1MB. - long threshold = length() / 100; + long long threshold = length() / 100; threshold = std::max(threshold, MinPaddingLength); threshold = std::min(threshold, MaxPaddingLegnth); @@ -208,10 +212,10 @@ bool FLAC::File::save() { paddingLength = MinPaddingLength; } - ByteVector paddingHeader = ByteVector::fromUInt(paddingLength); + ByteVector paddingHeader = ByteVector::fromUInt32BE(paddingLength); paddingHeader[0] = static_cast(MetadataBlock::Padding | LastBlockFlag); data.append(paddingHeader); - data.resize(static_cast(data.size() + paddingLength)); + data.resize(static_cast(data.size() + paddingLength)); // Write the data to the file @@ -304,7 +308,7 @@ List FLAC::File::pictureList() { List pictures; for (BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { - Picture *picture = dynamic_cast(*it); + Picture *picture = dynamic_cast(it->get()); if (picture) { pictures.append(picture); } @@ -314,25 +318,21 @@ List FLAC::File::pictureList() { } void FLAC::File::addPicture(Picture *picture) { - d->blocks.append(picture); + d->blocks.append(std::shared_ptr(picture)); } -void FLAC::File::removePicture(Picture *picture, bool del) { +void FLAC::File::removePicture(Picture *picture) { BlockIterator it = d->blocks.find(picture); if (it != d->blocks.end()) d->blocks.erase(it); - if (del) - delete picture; - } void FLAC::File::removePictures() { for (BlockIterator it = d->blocks.begin(); it != d->blocks.end();) { - if (dynamic_cast(*it)) { - delete *it; + if (dynamic_cast(it->get())) { it = d->blocks.erase(it); } else { @@ -409,14 +409,14 @@ void FLAC::File::read(bool readProperties) { const ByteVector infoData = d->blocks.front()->render(); - long streamLength; + long long streamLength; if (d->ID3v1Location >= 0) streamLength = d->ID3v1Location - d->streamStart; else streamLength = length() - d->streamStart; - d->properties = new AudioProperties(infoData, streamLength); + d->properties.reset(new AudioProperties(infoData, streamLength)); } } @@ -431,7 +431,7 @@ void FLAC::File::scan() { if (!isValid()) return; - long nextBlockOffset; + long long nextBlockOffset; if (d->ID3v2Location >= 0) nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize); @@ -466,7 +466,7 @@ void FLAC::File::scan() { const char blockType = header[0] & ~LastBlockFlag; const bool isLastBlock = (header[0] & LastBlockFlag) != 0; - const unsigned int blockLength = header.toUInt(1U, 3U); + const size_t blockLength = header.toUInt24BE(1); // First block should be the stream_info metadata @@ -489,33 +489,32 @@ void FLAC::File::scan() { return; } - MetadataBlock *block = nullptr; + std::shared_ptr block; // Found the vorbis-comment if (blockType == MetadataBlock::VorbisComment) { if (d->xiphCommentData.isEmpty()) { d->xiphCommentData = data; - block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, data); + block.reset(new UnknownMetadataBlock(MetadataBlock::VorbisComment, data)); } else { debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, discarding"); } } else if (blockType == MetadataBlock::Picture) { - FLAC::Picture *picture = new FLAC::Picture(); + std::shared_ptr picture(new FLAC::Picture()); if (picture->parse(data)) { block = picture; } else { debug("FLAC::File::scan() -- invalid picture found, discarding"); - delete picture; } } else if (blockType == MetadataBlock::Padding) { // Skip all padding blocks. } else { - block = new UnknownMetadataBlock(blockType, data); + block.reset(new UnknownMetadataBlock(blockType, data)); } if (block) diff --git a/3rdparty/taglib/flac/flacfile.h b/3rdparty/taglib/flac/flacfile.h index b21a9bf39..66c9df594 100644 --- a/3rdparty/taglib/flac/flacfile.h +++ b/3rdparty/taglib/flac/flacfile.h @@ -26,6 +26,8 @@ #ifndef TAGLIB_FLACFILE_H #define TAGLIB_FLACFILE_H +#include + #include "taglib_export.h" #include "tfile.h" #include "tlist.h" @@ -97,7 +99,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * * \note In the current implementation, \a propertiesStyle is ignored. */ - explicit File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); + explicit File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average, ID3v2::FrameFactory *frameFactory = nullptr); /*! * Constructs a FLAC file from \a stream. If \a readProperties is true the file's audio properties will also be read. @@ -109,12 +111,12 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \note In the current implementation, \a propertiesStyle is ignored. */ // BIC: merge with the above constructor - explicit File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); + explicit File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average, ID3v2::FrameFactory *frameFactory = nullptr); /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. This will be a union of XiphComment, ID3v1 and ID3v2 tags. @@ -123,27 +125,19 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \see ID3v1Tag() * \see XiphComment() */ - virtual Strawberry_TagLib::TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains more than one tag (e.g. XiphComment and ID3v1), only the first one (in the order XiphComment, ID3v2, ID3v1) will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &); + Strawberry_TagLib::TagLib::Tag *tag() const override; /*! * Implements the unified property interface -- import function. * This always creates a Xiph comment, if none exists. The return value relates to the Xiph comment only. * Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed in the FLAC specification. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; /*! * Returns the FLAC::AudioProperties for this file. If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. This will primarily save the XiphComment, but will also keep any old ID3-tags up to date. @@ -151,7 +145,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Returns a pointer to the ID3v2 tag of the file. @@ -208,10 +202,9 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { List pictureList(); /*! - * Removes an attached picture. - * If \a del is true the picture's memory will be freed; if it is false, it must be deleted by the user. + * Removes an attached picture. The picture's memory will be freed. */ - void removePicture(Picture *picture, bool del = true); + void removePicture(Picture *picture); /*! * Remove all attached images. @@ -269,7 +262,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/flac/flacmetadatablock.cpp b/3rdparty/taglib/flac/flacmetadatablock.cpp index 30871c7af..c4138bf1a 100644 --- a/3rdparty/taglib/flac/flacmetadatablock.cpp +++ b/3rdparty/taglib/flac/flacmetadatablock.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "taglib.h" +#include "tdebug.h" #include "flacmetadatablock.h" using namespace Strawberry_TagLib::TagLib; diff --git a/3rdparty/taglib/flac/flacmetadatablock.h b/3rdparty/taglib/flac/flacmetadatablock.h index b24ebe65c..ba3dbd7a1 100644 --- a/3rdparty/taglib/flac/flacmetadatablock.h +++ b/3rdparty/taglib/flac/flacmetadatablock.h @@ -60,7 +60,7 @@ class TAGLIB_EXPORT MetadataBlock { virtual ByteVector render() const = 0; private: - explicit MetadataBlock(const MetadataBlock &item); + MetadataBlock(const MetadataBlock &item); MetadataBlock &operator=(const MetadataBlock &item); class MetadataBlockPrivate; diff --git a/3rdparty/taglib/flac/flacpicture.cpp b/3rdparty/taglib/flac/flacpicture.cpp index 0546a0377..8593efbd7 100644 --- a/3rdparty/taglib/flac/flacpicture.cpp +++ b/3rdparty/taglib/flac/flacpicture.cpp @@ -23,19 +23,19 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "taglib.h" +#include "tdebug.h" #include "flacpicture.h" using namespace Strawberry_TagLib::TagLib; class FLAC::Picture::PicturePrivate { public: - PicturePrivate() : type(FLAC::Picture::Other), - width(0), - height(0), - colorDepth(0), - numColors(0) { + explicit PicturePrivate() : type(FLAC::Picture::Other), + width(0), + height(0), + colorDepth(0), + numColors(0) { } Type type; @@ -70,10 +70,10 @@ bool FLAC::Picture::parse(const ByteVector &data) { return false; } - unsigned int pos = 0; - d->type = FLAC::Picture::Type(data.toUInt(pos)); + size_t pos = 0; + d->type = FLAC::Picture::Type(data.toUInt32BE(pos)); pos += 4; - unsigned int mimeTypeLength = data.toUInt(pos); + const unsigned int mimeTypeLength = data.toUInt32BE(pos); pos += 4; if (pos + mimeTypeLength + 24 > data.size()) { debug("Invalid picture block."); @@ -81,7 +81,7 @@ bool FLAC::Picture::parse(const ByteVector &data) { } d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8); pos += mimeTypeLength; - unsigned int descriptionLength = data.toUInt(pos); + const unsigned int descriptionLength = data.toUInt32BE(pos); pos += 4; if (pos + descriptionLength + 20 > data.size()) { debug("Invalid picture block."); @@ -89,15 +89,15 @@ bool FLAC::Picture::parse(const ByteVector &data) { } d->description = String(data.mid(pos, descriptionLength), String::UTF8); pos += descriptionLength; - d->width = data.toUInt(pos); + d->width = data.toUInt32BE(pos); pos += 4; - d->height = data.toUInt(pos); + d->height = data.toUInt32BE(pos); pos += 4; - d->colorDepth = data.toUInt(pos); + d->colorDepth = data.toUInt32BE(pos); pos += 4; - d->numColors = data.toUInt(pos); + d->numColors = data.toUInt32BE(pos); pos += 4; - unsigned int dataLength = data.toUInt(pos); + const unsigned int dataLength = data.toUInt32BE(pos); pos += 4; if (pos + dataLength > data.size()) { debug("Invalid picture block."); @@ -112,18 +112,18 @@ bool FLAC::Picture::parse(const ByteVector &data) { ByteVector FLAC::Picture::render() const { ByteVector result; - result.append(ByteVector::fromUInt(d->type)); + result.append(ByteVector::fromUInt32BE(d->type)); ByteVector mimeTypeData = d->mimeType.data(String::UTF8); - result.append(ByteVector::fromUInt(mimeTypeData.size())); + result.append(ByteVector::fromUInt32BE(mimeTypeData.size())); result.append(mimeTypeData); ByteVector descriptionData = d->description.data(String::UTF8); - result.append(ByteVector::fromUInt(descriptionData.size())); + result.append(ByteVector::fromUInt32BE(descriptionData.size())); result.append(descriptionData); - result.append(ByteVector::fromUInt(d->width)); - result.append(ByteVector::fromUInt(d->height)); - result.append(ByteVector::fromUInt(d->colorDepth)); - result.append(ByteVector::fromUInt(d->numColors)); - result.append(ByteVector::fromUInt(d->data.size())); + result.append(ByteVector::fromUInt32BE(d->width)); + result.append(ByteVector::fromUInt32BE(d->height)); + result.append(ByteVector::fromUInt32BE(d->colorDepth)); + result.append(ByteVector::fromUInt32BE(d->numColors)); + result.append(ByteVector::fromUInt32BE(d->data.size())); result.append(d->data); return result; diff --git a/3rdparty/taglib/flac/flacpicture.h b/3rdparty/taglib/flac/flacpicture.h index 1dcb805b0..2fc84a871 100644 --- a/3rdparty/taglib/flac/flacpicture.h +++ b/3rdparty/taglib/flac/flacpicture.h @@ -89,7 +89,7 @@ class TAGLIB_EXPORT Picture : public MetadataBlock { explicit Picture(); explicit Picture(const ByteVector &data); - ~Picture(); + ~Picture() override; /*! * Returns the type of the image. @@ -176,12 +176,12 @@ class TAGLIB_EXPORT Picture : public MetadataBlock { /*! * Returns the FLAC metadata block type. */ - int code() const; + int code() const override; /*! * Render the content to the FLAC picture block format. */ - ByteVector render() const; + ByteVector render() const override; /*! * Parse the picture data in the FLAC picture block format. @@ -189,15 +189,13 @@ class TAGLIB_EXPORT Picture : public MetadataBlock { bool parse(const ByteVector &rawData); private: - explicit Picture(const Picture &item); + Picture(const Picture &item); Picture &operator=(const Picture &item); class PicturePrivate; PicturePrivate *d; }; -typedef List PictureList; - } // namespace FLAC } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/flac/flacproperties.cpp b/3rdparty/taglib/flac/flacproperties.cpp index 64960fbc6..b91ba6853 100644 --- a/3rdparty/taglib/flac/flacproperties.cpp +++ b/3rdparty/taglib/flac/flacproperties.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "flacproperties.h" #include "flacfile.h" @@ -33,12 +33,12 @@ using namespace Strawberry_TagLib::TagLib; class FLAC::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - bitsPerSample(0), - channels(0), - sampleFrames(0) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + bitsPerSample(0), + channels(0), + sampleFrames(0) {} int length; int bitrate; @@ -53,7 +53,7 @@ class FLAC::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -FLAC::AudioProperties::AudioProperties(const ByteVector &data, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +FLAC::AudioProperties::AudioProperties(const ByteVector &data, long long streamLength, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(data, streamLength); } @@ -97,14 +97,14 @@ ByteVector FLAC::AudioProperties::signature() const { // private members //////////////////////////////////////////////////////////////////////////////// -void FLAC::AudioProperties::read(const ByteVector &data, long streamLength) { +void FLAC::AudioProperties::read(const ByteVector &data, long long streamLength) { if (data.size() < 18) { debug("FLAC::AudioProperties::read() - FLAC properties must contain at least 18 bytes."); return; } - unsigned int pos = 0; + size_t pos = 0; // Minimum block size (in samples) pos += 2; @@ -118,7 +118,7 @@ void FLAC::AudioProperties::read(const ByteVector &data, long streamLength) { // Maximum frame size (in bytes) pos += 3; - const unsigned int flags = data.toUInt(pos, true); + const unsigned int flags = data.toUInt32BE(pos); pos += 4; d->sampleRate = flags >> 12; @@ -129,7 +129,7 @@ void FLAC::AudioProperties::read(const ByteVector &data, long streamLength) { // stream length in samples. (Audio files measured in days) const unsigned long long hi = flags & 0xf; - const unsigned long long lo = data.toUInt(pos, true); + const unsigned long long lo = data.toUInt32BE(pos); pos += 4; d->sampleFrames = (hi << 32) | lo; diff --git a/3rdparty/taglib/flac/flacproperties.h b/3rdparty/taglib/flac/flacproperties.h index b3d4cc282..1cc19dfc9 100644 --- a/3rdparty/taglib/flac/flacproperties.h +++ b/3rdparty/taglib/flac/flacproperties.h @@ -47,41 +47,41 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of FLAC::AudioProperties with the data read from the ByteVector \a data. */ - explicit AudioProperties(const ByteVector &data, long streamLength, ReadStyle style = Average); + explicit AudioProperties(const ByteVector &data, long long streamLength, ReadStyle style = Average); /*! * Destroys this FLAC::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample as read from the FLAC identification header. @@ -99,10 +99,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro ByteVector signature() const; private: - explicit AudioProperties(const AudioProperties &); - AudioProperties &operator=(const AudioProperties &); - - void read(const ByteVector &data, long streamLength); + void read(const ByteVector &data, long long streamLength); class AudioPropertiesPrivate; AudioPropertiesPrivate *d; diff --git a/3rdparty/taglib/flac/flacunknownmetadatablock.cpp b/3rdparty/taglib/flac/flacunknownmetadatablock.cpp index 9534c0ec3..5ef473fff 100644 --- a/3rdparty/taglib/flac/flacunknownmetadatablock.cpp +++ b/3rdparty/taglib/flac/flacunknownmetadatablock.cpp @@ -23,16 +23,16 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "taglib.h" +#include "tdebug.h" +#include "tstring.h" #include "flacunknownmetadatablock.h" using namespace Strawberry_TagLib::TagLib; class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate { public: - UnknownMetadataBlockPrivate() : code(0) {} + explicit UnknownMetadataBlockPrivate() : code(0) {} int code; ByteVector data; diff --git a/3rdparty/taglib/flac/flacunknownmetadatablock.h b/3rdparty/taglib/flac/flacunknownmetadatablock.h index d23375382..c23afc221 100644 --- a/3rdparty/taglib/flac/flacunknownmetadatablock.h +++ b/3rdparty/taglib/flac/flacunknownmetadatablock.h @@ -38,12 +38,12 @@ namespace FLAC { class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock { public: explicit UnknownMetadataBlock(int code, const ByteVector &data); - ~UnknownMetadataBlock(); + ~UnknownMetadataBlock() override; /*! * Returns the FLAC metadata block type. */ - int code() const; + int code() const override; /*! * Sets the FLAC metadata block type. @@ -63,7 +63,7 @@ class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock { /*! * Render the content of the block. */ - ByteVector render() const; + ByteVector render() const override; private: explicit UnknownMetadataBlock(const MetadataBlock &item); diff --git a/3rdparty/taglib/it/itfile.cpp b/3rdparty/taglib/it/itfile.cpp index 2ade04dd8..38dfcc841 100644 --- a/3rdparty/taglib/it/itfile.cpp +++ b/3rdparty/taglib/it/itfile.cpp @@ -41,16 +41,14 @@ class IT::File::FilePrivate { IT::AudioProperties properties; }; -IT::File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) { +IT::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) { if (isOpen()) read(readProperties); } -IT::File::File(IOStream *stream, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) { +IT::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) { if (isOpen()) read(readProperties); @@ -94,7 +92,7 @@ bool IT::File::save() { StringList lines = d->tag.comment().split("\n"); for (unsigned short i = 0; i < instrumentCount; ++i) { seek(192L + length + (static_cast(i) << 2)); - unsigned long instrumentOffset = 0; + unsigned int instrumentOffset = 0; if (!readU32L(instrumentOffset)) return false; @@ -109,7 +107,7 @@ bool IT::File::save() { for (unsigned short i = 0; i < sampleCount; ++i) { seek(192L + length + (static_cast(instrumentCount) << 2) + (static_cast(i) << 2)); - unsigned long sampleOffset = 0; + unsigned int sampleOffset = 0; if (!readU32L(sampleOffset)) return false; @@ -136,13 +134,13 @@ bool IT::File::save() { unsigned short special = 0; unsigned short messageLength = 0; - unsigned long messageOffset = 0; + unsigned int messageOffset = 0; seek(46); if (!readU16L(special)) return false; - unsigned long fileSize = File::length(); + unsigned int fileSize = File::length(); if (special & AudioProperties::MessageAttached) { seek(54); if (!readU16L(messageLength) || !readU32L(messageOffset)) @@ -217,8 +215,8 @@ void IT::File::read(bool) { seek(messageOffset); ByteVector messageBytes = readBlock(messageLength); READ_ASSERT(messageBytes.size() == messageLength); - int index = messageBytes.find(static_cast(0)); - if (index > -1) + const size_t index = messageBytes.find(static_cast(0)); + if (index != ByteVector::npos()) messageBytes.resize(index, 0); messageBytes.replace('\r', '\n'); message = messageBytes; diff --git a/3rdparty/taglib/it/itfile.h b/3rdparty/taglib/it/itfile.h index f224149b8..b4eaac260 100644 --- a/3rdparty/taglib/it/itfile.h +++ b/3rdparty/taglib/it/itfile.h @@ -56,15 +56,15 @@ class TAGLIB_EXPORT File : public Mod::FileBase { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; - Mod::Tag *tag() const; + Mod::Tag *tag() const override; /*! * Returns the IT::AudioProperties for this file. If no audio properties * were read then this will return a null pointer. */ - IT::AudioProperties *audioProperties() const; + IT::AudioProperties *audioProperties() const override; /*! * Save the file. @@ -72,10 +72,10 @@ class TAGLIB_EXPORT File : public Mod::FileBase { * * \note Saving Impulse Tracker tags is not supported. */ - bool save(); + bool save() override; private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/it/itproperties.cpp b/3rdparty/taglib/it/itproperties.cpp index b966e5cc2..19636775e 100644 --- a/3rdparty/taglib/it/itproperties.cpp +++ b/3rdparty/taglib/it/itproperties.cpp @@ -31,21 +31,21 @@ using namespace IT; class IT::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : channels(0), - lengthInPatterns(0), - instrumentCount(0), - sampleCount(0), - patternCount(0), - version(0), - compatibleVersion(0), - flags(0), - special(0), - globalVolume(0), - mixVolume(0), - tempo(0), - bpmSpeed(0), - panningSeparation(0), - pitchWheelDepth(0) { + explicit AudioPropertiesPrivate() : channels(0), + lengthInPatterns(0), + instrumentCount(0), + sampleCount(0), + patternCount(0), + version(0), + compatibleVersion(0), + flags(0), + special(0), + globalVolume(0), + mixVolume(0), + tempo(0), + bpmSpeed(0), + panningSeparation(0), + pitchWheelDepth(0) { } int channels; @@ -65,7 +65,7 @@ class IT::AudioProperties::AudioPropertiesPrivate { unsigned char pitchWheelDepth; }; -IT::AudioProperties::AudioProperties(AudioProperties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::AudioProperties(propertiesStyle), d(new AudioPropertiesPrivate()) {} +IT::AudioProperties::AudioProperties(AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) {} IT::AudioProperties::~AudioProperties() { delete d; @@ -151,6 +151,10 @@ unsigned char IT::AudioProperties::pitchWheelDepth() const { return d->pitchWheelDepth; } +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + void IT::AudioProperties::setChannels(int channels) { d->channels = channels; } diff --git a/3rdparty/taglib/it/itproperties.h b/3rdparty/taglib/it/itproperties.h index 325ca6de0..9b8044de5 100644 --- a/3rdparty/taglib/it/itproperties.h +++ b/3rdparty/taglib/it/itproperties.h @@ -54,14 +54,14 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro MidiConfEmbedded = 8 }; - explicit AudioProperties(AudioProperties::ReadStyle propertiesStyle); - virtual ~AudioProperties(); + explicit AudioProperties(AudioProperties::ReadStyle); + ~AudioProperties() override; - int lengthInSeconds() const; - int lengthInMilliseconds() const; - int bitrate() const; - int sampleRate() const; - int channels() const; + int lengthInSeconds() const override; + int lengthInMilliseconds() const override; + int bitrate() const override; + int sampleRate() const override; + int channels() const override; unsigned short lengthInPatterns() const; bool stereo() const; @@ -79,6 +79,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro unsigned char panningSeparation() const; unsigned char pitchWheelDepth() const; + private: void setChannels(int channels); void setLengthInPatterns(unsigned short lengthInPatterns); void setInstrumentCount(unsigned short instrumentCount); @@ -96,9 +97,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro void setPitchWheelDepth(unsigned char pitchWheelDepth); private: - explicit AudioProperties(const AudioProperties &); - AudioProperties &operator=(const AudioProperties &); - class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; diff --git a/3rdparty/taglib/mod/modfile.cpp b/3rdparty/taglib/mod/modfile.cpp index 3bc705f2f..e02e459f1 100644 --- a/3rdparty/taglib/mod/modfile.cpp +++ b/3rdparty/taglib/mod/modfile.cpp @@ -67,14 +67,6 @@ Mod::AudioProperties *Mod::File::audioProperties() const { return &d->properties; } -PropertyMap Mod::File::properties() const { - return d->tag.properties(); -} - -PropertyMap Mod::File::setProperties(const PropertyMap &properties) { - return d->tag.setProperties(properties); -} - bool Mod::File::save() { if (readOnly()) { @@ -84,13 +76,13 @@ bool Mod::File::save() { seek(0); writeString(d->tag.title(), 20); StringList lines = d->tag.comment().split("\n"); - unsigned int n = std::min(lines.size(), d->properties.instrumentCount()); - for (unsigned int i = 0; i < n; ++i) { + size_t n = std::min(lines.size(), d->properties.instrumentCount()); + for (size_t i = 0; i < n; ++i) { writeString(lines[i], 22); seek(8, Current); } - for (unsigned int i = n; i < d->properties.instrumentCount(); ++i) { + for (size_t i = n; i < d->properties.instrumentCount(); ++i) { writeString(String(), 22); seek(8, Current); } diff --git a/3rdparty/taglib/mod/modfile.h b/3rdparty/taglib/mod/modfile.h index fbe3d269f..0d55d2780 100644 --- a/3rdparty/taglib/mod/modfile.h +++ b/3rdparty/taglib/mod/modfile.h @@ -61,25 +61,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; - Mod::Tag *tag() const; + Mod::Tag *tag() const override; - /*! - * Implements the unified property interface -- export function. - * Forwards to Mod::Tag::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Forwards to Mod::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); /*! * Returns the Mod::AudioProperties for this file. If no audio properties were read then this will return a null pointer. */ - Mod::AudioProperties *audioProperties() const; + Mod::AudioProperties *audioProperties() const override; /*! * Save the file. @@ -87,10 +76,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::Mod::FileBase { * * \note Saving Protracker tags is not supported. */ - bool save(); + bool save() override; private: - explicit File(const File &); + File(const File &); File &operator=(const File &); void read(bool readProperties); diff --git a/3rdparty/taglib/mod/modfilebase.cpp b/3rdparty/taglib/mod/modfilebase.cpp index a340b4f27..4643fb8fb 100644 --- a/3rdparty/taglib/mod/modfilebase.cpp +++ b/3rdparty/taglib/mod/modfilebase.cpp @@ -34,18 +34,18 @@ Mod::FileBase::FileBase(FileName file) : Strawberry_TagLib::TagLib::File(file) { Mod::FileBase::FileBase(IOStream *stream) : Strawberry_TagLib::TagLib::File(stream) {} -void Mod::FileBase::writeString(const String &s, unsigned long size, char padding) { +void Mod::FileBase::writeString(const String &s, unsigned int size, char padding) { ByteVector data(s.data(String::Latin1)); data.resize(size, padding); writeBlock(data); } -bool Mod::FileBase::readString(String &s, unsigned long size) { +bool Mod::FileBase::readString(String &s, unsigned int size) { ByteVector data(readBlock(size)); if (data.size() < size) return false; - int index = data.find(static_cast(0)); - if (index > -1) { + const size_t index = data.find(static_cast(0)); + if (index != ByteVector::npos()) { data.resize(index); } data.replace('\xff', ' '); @@ -61,19 +61,19 @@ void Mod::FileBase::writeByte(unsigned char _byte) { } void Mod::FileBase::writeU16L(unsigned short number) { - writeBlock(ByteVector::fromShort(number, false)); + writeBlock(ByteVector::fromUInt16LE(number)); } -void Mod::FileBase::writeU32L(unsigned long number) { - writeBlock(ByteVector::fromUInt(number, false)); +void Mod::FileBase::writeU32L(unsigned int number) { + writeBlock(ByteVector::fromUInt32LE(number)); } void Mod::FileBase::writeU16B(unsigned short number) { - writeBlock(ByteVector::fromShort(number, true)); + writeBlock(ByteVector::fromUInt16BE(number)); } -void Mod::FileBase::writeU32B(unsigned long number) { - writeBlock(ByteVector::fromUInt(number, true)); +void Mod::FileBase::writeU32B(unsigned int number) { + writeBlock(ByteVector::fromUInt32BE(number)); } bool Mod::FileBase::readByte(unsigned char &_byte) { @@ -89,16 +89,16 @@ bool Mod::FileBase::readU16L(unsigned short &number) { ByteVector data(readBlock(2)); if (data.size() < 2) return false; - number = data.toUShort(false); + number = data.toUInt16LE(0); return true; } -bool Mod::FileBase::readU32L(unsigned long &number) { +bool Mod::FileBase::readU32L(unsigned int &number) { ByteVector data(readBlock(4)); if (data.size() < 4) return false; - number = data.toUInt(false); + number = data.toUInt32LE(0); return true; } @@ -107,16 +107,16 @@ bool Mod::FileBase::readU16B(unsigned short &number) { ByteVector data(readBlock(2)); if (data.size() < 2) return false; - number = data.toUShort(true); + number = data.toUInt16BE(0); return true; } -bool Mod::FileBase::readU32B(unsigned long &number) { +bool Mod::FileBase::readU32B(unsigned int &number) { ByteVector data(readBlock(4)); if (data.size() < 4) return false; - number = data.toUInt(true); + number = data.toUInt32BE(0); return true; } diff --git a/3rdparty/taglib/mod/modfilebase.h b/3rdparty/taglib/mod/modfilebase.h index 9f857404b..b1e7512c1 100644 --- a/3rdparty/taglib/mod/modfilebase.h +++ b/3rdparty/taglib/mod/modfilebase.h @@ -43,19 +43,19 @@ class TAGLIB_EXPORT FileBase : public Strawberry_TagLib::TagLib::File { explicit FileBase(FileName file); explicit FileBase(IOStream *stream); - void writeString(const String &s, unsigned long size, char padding = 0); + void writeString(const String &s, unsigned int size, char padding = 0); void writeByte(unsigned char byte); void writeU16L(unsigned short number); - void writeU32L(unsigned long number); + void writeU32L(unsigned int number); void writeU16B(unsigned short number); - void writeU32B(unsigned long number); + void writeU32B(unsigned int number); - bool readString(String &s, unsigned long size); - bool readByte(unsigned char &byte); + bool readString(String &s, unsigned int size); + bool readByte(unsigned char &_byte); bool readU16L(unsigned short &number); - bool readU32L(unsigned long &number); + bool readU32L(unsigned int &number); bool readU16B(unsigned short &number); - bool readU32B(unsigned long &number); + bool readU32B(unsigned int &number); }; } // namespace Mod diff --git a/3rdparty/taglib/mod/modfileprivate.h b/3rdparty/taglib/mod/modfileprivate.h index d21916537..459ddf8fd 100644 --- a/3rdparty/taglib/mod/modfileprivate.h +++ b/3rdparty/taglib/mod/modfileprivate.h @@ -38,9 +38,9 @@ #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_U32L(setter) READ(setter, unsigned int, readU32L) #define READ_U16B(setter) READ(setter, unsigned short, readU16B) -#define READ_U32B(setter) READ(setter, unsigned long, readU32B) +#define READ_U32B(setter) READ(setter, unsigned int, readU32B) #define READ_STRING(setter, size) \ { \ @@ -55,9 +55,9 @@ #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_U32L_AS(name) READ_AS(unsigned int, 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_U32B_AS(name) READ_AS(unsigned int, name, readU32B) #define READ_STRING_AS(name, size) \ String name; \ diff --git a/3rdparty/taglib/mod/modproperties.cpp b/3rdparty/taglib/mod/modproperties.cpp index 44c80acb5..24caf2613 100644 --- a/3rdparty/taglib/mod/modproperties.cpp +++ b/3rdparty/taglib/mod/modproperties.cpp @@ -31,14 +31,18 @@ using namespace Mod; class Mod::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : channels(0), instrumentCount(0), lengthInPatterns(0) {} + explicit AudioPropertiesPrivate() : channels(0), instrumentCount(0), lengthInPatterns(0) {} int channels; unsigned int instrumentCount; unsigned char lengthInPatterns; }; -Mod::AudioProperties::AudioProperties(AudioProperties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::AudioProperties(propertiesStyle), d(new AudioPropertiesPrivate()) { +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Mod::AudioProperties::AudioProperties(AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { } Mod::AudioProperties::~AudioProperties() { @@ -73,6 +77,10 @@ unsigned char Mod::AudioProperties::lengthInPatterns() const { return d->lengthInPatterns; } +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + void Mod::AudioProperties::setChannels(int channels) { d->channels = channels; } diff --git a/3rdparty/taglib/mod/modproperties.h b/3rdparty/taglib/mod/modproperties.h index 4f4c9c7ef..91ca355b5 100644 --- a/3rdparty/taglib/mod/modproperties.h +++ b/3rdparty/taglib/mod/modproperties.h @@ -34,30 +34,27 @@ namespace TagLib { namespace Mod { class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioProperties { + friend class File; + public: explicit AudioProperties(AudioProperties::ReadStyle propertiesStyle); - virtual ~AudioProperties(); + ~AudioProperties() override; - int lengthInSeconds() const; - int lengthInMilliseconds() const; - int bitrate() const; - int sampleRate() const; - int channels() const; + int lengthInSeconds() const override; + int lengthInMilliseconds() const override; + int bitrate() const override; + int sampleRate() const override; + int channels() const override; unsigned int instrumentCount() const; unsigned char lengthInPatterns() const; + private: void setChannels(int channels); void setInstrumentCount(unsigned int instrumentCount); void setLengthInPatterns(unsigned char lengthInPatterns); - private: - friend class File; - - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; diff --git a/3rdparty/taglib/mod/modtag.cpp b/3rdparty/taglib/mod/modtag.cpp index e224e2ebf..0f7c58c37 100644 --- a/3rdparty/taglib/mod/modtag.cpp +++ b/3rdparty/taglib/mod/modtag.cpp @@ -27,13 +27,14 @@ #include "modtag.h" #include "tstringlist.h" #include "tpropertymap.h" +#include "tpicturemap.h" using namespace Strawberry_TagLib::TagLib; using namespace Mod; class Mod::Tag::TagPrivate { public: - TagPrivate() {} + explicit TagPrivate() {} String title; String comment; @@ -74,6 +75,10 @@ unsigned int Mod::Tag::track() const { return 0; } +Strawberry_TagLib::TagLib::PictureMap Mod::Tag::pictures() const { + return PictureMap(); +} + String Mod::Tag::trackerName() const { return d->trackerName; } @@ -101,6 +106,8 @@ void Mod::Tag::setYear(unsigned int) { void Mod::Tag::setTrack(unsigned int) { } +void Mod::Tag::setPictures(const PictureMap&) {} + void Mod::Tag::setTrackerName(const String &trackerName) { d->trackerName = trackerName; } diff --git a/3rdparty/taglib/mod/modtag.h b/3rdparty/taglib/mod/modtag.h index bd285be49..067c60af5 100644 --- a/3rdparty/taglib/mod/modtag.h +++ b/3rdparty/taglib/mod/modtag.h @@ -47,43 +47,45 @@ namespace Mod { class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { public: explicit Tag(); - virtual ~Tag(); + ~Tag() override; /*! * Returns the track name; if no track name is present in the tag String::null will be returned. */ - virtual String title() const; + String title() const override; /*! * Not supported by module files. Therefore always returns String::null. */ - virtual String artist() const; + String artist() const override; /*! * Not supported by module files. Therefore always returns String::null. */ - virtual String album() const; + String album() const override; /*! * Returns the track comment derived from the instrument/sample/pattern * names; if no comment is present in the tag String::null will be returned. */ - virtual String comment() const; + String comment() const override; /*! * Not supported by module files. Therefore always returns String::null. */ - virtual String genre() const; + String genre() const override; /*! * Not supported by module files. Therefore always returns 0. */ - virtual unsigned int year() const; + unsigned int year() const override; /*! * Not supported by module files. Therefore always returns 0. */ - virtual unsigned int track() const; + unsigned int track() const override; + + PictureMap pictures() const override; /*! * Returns the name of the tracker used to create/edit the module file. @@ -100,17 +102,17 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * The length limits per file type are (1 character = 1 byte): * Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 characters. */ - virtual void setTitle(const String &title); + void setTitle(const String &title) override; /*! * Not supported by module files and therefore ignored. */ - virtual void setArtist(const String &artist); + void setArtist(const String &artist) override; /*! * Not supported by module files and therefore ignored. */ - virtual void setAlbum(const String &album); + void setAlbum(const String &album) override; /*! * Sets the comment to \a comment. @@ -126,22 +128,24 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * The line length limits per file type are (1 character = 1 byte): * Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22 characters. */ - virtual void setComment(const String &comment); + void setComment(const String &comment) override; /*! * Not supported by module files and therefore ignored. */ - virtual void setGenre(const String &genre); + void setGenre(const String &genre) override; /*! * Not supported by module files and therefore ignored. */ - virtual void setYear(unsigned int year); + void setYear(unsigned int year) override; /*! * Not supported by module files and therefore ignored. */ - virtual void setTrack(unsigned int track); + void setTrack(unsigned int track) override; + + void setPictures(const PictureMap &l) override; /*! * Sets the tracker name to \a trackerName. @@ -158,17 +162,17 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * Implements the unified property interface -- export function. * Since the module tag is very limited, the exported map is as well. */ - PropertyMap properties() const; + PropertyMap properties() const override; /*! * Implements the unified property interface -- import function. * Because of the limitations of the module file tag, any tags besides COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be returned. * Additionally, if the map contains tags with multiple values, all but the first will be contained in the returned map of unsupported properties. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; private: - explicit Tag(const Tag&); + Tag(const Tag&); Tag &operator=(const Tag&); class TagPrivate; diff --git a/3rdparty/taglib/mp4/mp4atom.cpp b/3rdparty/taglib/mp4/mp4atom.cpp index e157c7b91..de2c70ebc 100644 --- a/3rdparty/taglib/mp4/mp4atom.cpp +++ b/3rdparty/taglib/mp4/mp4atom.cpp @@ -25,8 +25,8 @@ #include -#include -#include +#include "tdebug.h" +#include "tstring.h" #include "mp4atom.h" using namespace Strawberry_TagLib::TagLib; @@ -48,7 +48,7 @@ MP4::Atom::Atom(File *file) { return; } - length = header.toUInt(); + length = header.toUInt32BE(0); if (length == 0) { // The last atom which extends to the end of the file. @@ -56,17 +56,7 @@ MP4::Atom::Atom(File *file) { } else if (length == 1) { // The atom has a 64-bit length. - const long long longLength = file->readBlock(8).toLongLong(); - if (longLength <= LONG_MAX) { - // The actual length fits in long. That's always the case if long is 64-bit. - length = static_cast(longLength); - } - else { - debug("MP4: 64-bit atoms are not supported"); - length = 0; - file->seek(0, File::End); - return; - } + length = file->readBlock(8).toInt64BE(0); } if (length < 8) { @@ -151,7 +141,7 @@ MP4::Atoms::Atoms(File *file) { atoms.setAutoDelete(true); file->seek(0, File::End); - long end = file->tell(); + long long end = file->tell(); file->seek(0); while (file->tell() + 8 <= end) { MP4::Atom *atom = new MP4::Atom(file); diff --git a/3rdparty/taglib/mp4/mp4atom.h b/3rdparty/taglib/mp4/mp4atom.h index fb86f28cd..336241787 100644 --- a/3rdparty/taglib/mp4/mp4atom.h +++ b/3rdparty/taglib/mp4/mp4atom.h @@ -78,11 +78,11 @@ class Atom { explicit 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); + Atom *find(const char *name1, const char *name2 = nullptr, const char *name3 = nullptr, const char *name4 = nullptr); + bool path(AtomList &path, const char *name1, const char *name2 = nullptr, const char *name3 = nullptr); AtomList findall(const char *name, bool recursive = false); - long offset; - long length; + long long offset; + long long length; Strawberry_TagLib::TagLib::ByteVector name; AtomList children; @@ -97,8 +97,8 @@ class Atoms { explicit 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); + Atom *find(const char *name1, const char *name2 = nullptr, const char *name3 = nullptr, const char *name4 = nullptr); + AtomList path(const char *name1, const char *name2 = nullptr, const char *name3 = nullptr, const char *name4 = nullptr); AtomList atoms; }; diff --git a/3rdparty/taglib/mp4/mp4coverart.cpp b/3rdparty/taglib/mp4/mp4coverart.cpp index 536b73fc5..4d9e4c85f 100644 --- a/3rdparty/taglib/mp4/mp4coverart.cpp +++ b/3rdparty/taglib/mp4/mp4coverart.cpp @@ -23,33 +23,40 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include "trefcounter.h" +#include + +#include "taglib.h" +#include "tdebug.h" #include "mp4coverart.h" using namespace Strawberry_TagLib::TagLib; -class MP4::CoverArt::CoverArtPrivate : public RefCounter { - public: - CoverArtPrivate() : format(MP4::CoverArt::JPEG) {} +namespace { - Format format; +struct CoverArtData { + MP4::CoverArt::Format format; ByteVector data; }; +} // namespace + +class MP4::CoverArt::CoverArtPrivate { + public: + explicit CoverArtPrivate(Format f, const ByteVector &v) : data(new CoverArtData()) { + data->format = f; + data->data = v; + } + + std::shared_ptr data; +}; + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -MP4::CoverArt::CoverArt(Format format, const ByteVector &data) : d(new CoverArtPrivate()) { - d->format = format; - d->data = data; -} +MP4::CoverArt::CoverArt(Format format, const ByteVector &data) : d(new CoverArtPrivate(format, data)) {} -MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d) { - d->ref(); -} +MP4::CoverArt::CoverArt(const CoverArt &item) : d(new CoverArtPrivate(*item.d)) {} MP4::CoverArt & MP4::CoverArt::operator=(const CoverArt &item) { @@ -64,17 +71,15 @@ void MP4::CoverArt::swap(CoverArt &item) { } MP4::CoverArt::~CoverArt() { - if (d->deref()) { - delete d; - } + delete d; } MP4::CoverArt::Format MP4::CoverArt::format() const { - return d->format; + return d->data->format; } ByteVector MP4::CoverArt::data() const { - return d->data; + return d->data->data; } diff --git a/3rdparty/taglib/mp4/mp4coverart.h b/3rdparty/taglib/mp4/mp4coverart.h index f6fafc665..d15765d09 100644 --- a/3rdparty/taglib/mp4/mp4coverart.h +++ b/3rdparty/taglib/mp4/mp4coverart.h @@ -51,7 +51,7 @@ class TAGLIB_EXPORT CoverArt { explicit CoverArt(Format format, const ByteVector &data); ~CoverArt(); - explicit CoverArt(const CoverArt &item); + CoverArt(const CoverArt &item); /*! * Copies the contents of \a item into this CoverArt. diff --git a/3rdparty/taglib/mp4/mp4file.cpp b/3rdparty/taglib/mp4/mp4file.cpp index 659726d4d..7cd45da53 100644 --- a/3rdparty/taglib/mp4/mp4file.cpp +++ b/3rdparty/taglib/mp4/mp4file.cpp @@ -23,10 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include +#include "tdebug.h" +#include "tstring.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "mp4atom.h" #include "mp4tag.h" @@ -53,7 +53,7 @@ bool checkValid(const MP4::AtomList &list) { class MP4::File::FilePrivate { public: - FilePrivate() : tag(nullptr), atoms(nullptr), properties(nullptr) {} + explicit FilePrivate() : tag(nullptr), atoms(nullptr), properties(nullptr) {} ~FilePrivate() { delete atoms; @@ -106,18 +106,6 @@ MP4::File::tag() const { return d->tag; } -PropertyMap MP4::File::properties() const { - return d->tag->properties(); -} - -void MP4::File::removeUnsupportedProperties(const StringList &properties) { - d->tag->removeUnsupportedProperties(properties); -} - -PropertyMap MP4::File::setProperties(const PropertyMap &properties) { - return d->tag->setProperties(properties); -} - MP4::AudioProperties * MP4::File::audioProperties() const { return d->properties; diff --git a/3rdparty/taglib/mp4/mp4file.h b/3rdparty/taglib/mp4/mp4file.h index 1c5e4c322..a02e34cfd 100644 --- a/3rdparty/taglib/mp4/mp4file.h +++ b/3rdparty/taglib/mp4/mp4file.h @@ -70,7 +70,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns a pointer to the MP4 tag of the file. @@ -80,34 +80,19 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \note The Tag is still owned by the MP4::File and should not be deleted by the user. * It will be deleted when the file (object) is destroyed. */ - Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function. - */ - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - */ - PropertyMap setProperties(const PropertyMap &); + Tag *tag() const override; /*! * Returns the MP4 audio properties for this file. */ - AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. * * This returns true if the save was successful. */ - bool save(); + bool save() override; /*! * Returns whether or not the file on disk actually has an MP4 tag, or the file has a Metadata Item List (ilst) atom. diff --git a/3rdparty/taglib/mp4/mp4item.cpp b/3rdparty/taglib/mp4/mp4item.cpp index a65029113..6f4439508 100644 --- a/3rdparty/taglib/mp4/mp4item.cpp +++ b/3rdparty/taglib/mp4/mp4item.cpp @@ -23,23 +23,25 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include "trefcounter.h" +#include + +#include "taglib.h" +#include "tdebug.h" #include "mp4item.h" +#include "tutils.h" using namespace Strawberry_TagLib::TagLib; -class MP4::Item::ItemPrivate : public RefCounter { - public: - ItemPrivate() : valid(true), atomDataType(TypeUndefined) {} +namespace { +struct ItemData { bool valid; - AtomDataType atomDataType; + MP4::AtomDataType atomDataType; + MP4::Item::ItemType type; union { bool m_bool; int m_int; - IntPair m_intPair; + MP4::Item::IntPair m_intPair; unsigned char m_byte; unsigned int m_uint; long long m_longlong; @@ -48,14 +50,24 @@ class MP4::Item::ItemPrivate : public RefCounter { ByteVectorList m_byteVectorList; MP4::CoverArtList m_coverArtList; }; +} // namespace + +class MP4::Item::ItemPrivate { + public: + explicit ItemPrivate() : data(new ItemData()) { + data->valid = true; + data->atomDataType = MP4::TypeUndefined; + data->type = MP4::Item::TypeUndefined; + } + + std::shared_ptr data; +}; MP4::Item::Item() : d(new ItemPrivate()) { - d->valid = false; + d->data->valid = false; } -MP4::Item::Item(const Item &item) : d(item.d) { - d->ref(); -} +MP4::Item::Item(const Item &item) : d(new ItemPrivate(*item.d)) {} MP4::Item &MP4::Item::operator=(const Item &item) { Item(item).swap(*this); @@ -69,91 +81,135 @@ void MP4::Item::swap(Item &item) { } MP4::Item::~Item() { - if (d->deref()) - delete d; + delete d; } MP4::Item::Item(bool value) : d(new ItemPrivate()) { - d->m_bool = value; + d->data->m_bool = value; + d->data->type = TypeBool; } MP4::Item::Item(int value) : d(new ItemPrivate()) { - d->m_int = value; + d->data->m_int = value; + d->data->type = TypeInt; } MP4::Item::Item(unsigned char value) : d(new ItemPrivate()) { - d->m_byte = value; + d->data->m_byte = value; + d->data->type = TypeByte; } MP4::Item::Item(unsigned int value) : d(new ItemPrivate()) { - d->m_uint = value; + d->data->m_uint = value; + d->data->type = TypeUInt; } MP4::Item::Item(long long value) : d(new ItemPrivate()) { - d->m_longlong = value; + d->data->m_longlong = value; + d->data->type = TypeLongLong; } -MP4::Item::Item(int first, int second) : d(new ItemPrivate()) { - d->m_intPair.first = first; - d->m_intPair.second = second; +MP4::Item::Item(int value1, int value2) : d(new ItemPrivate()) { + d->data->m_intPair.first = value1; + d->data->m_intPair.second = value2; + d->data->type = TypeIntPair; } MP4::Item::Item(const ByteVectorList &value) : d(new ItemPrivate()) { - d->m_byteVectorList = value; + d->data->m_byteVectorList = value; + d->data->type = TypeByteVectorList; } MP4::Item::Item(const StringList &value) : d(new ItemPrivate()) { - d->m_stringList = value; + d->data->m_stringList = value; + d->data->type = TypeStringList; } MP4::Item::Item(const MP4::CoverArtList &value) : d(new ItemPrivate()) { - d->m_coverArtList = value; + d->data->m_coverArtList = value; + d->data->type = TypeCoverArtList; } void MP4::Item::setAtomDataType(MP4::AtomDataType type) { - d->atomDataType = type; + d->data->atomDataType = type; } MP4::AtomDataType MP4::Item::atomDataType() const { - return d->atomDataType; + return d->data->atomDataType; } bool MP4::Item::toBool() const { - return d->m_bool; + return d->data->m_bool; } int MP4::Item::toInt() const { - return d->m_int; + return d->data->m_int; } unsigned char MP4::Item::toByte() const { - return d->m_byte; + return d->data->m_byte; } unsigned int MP4::Item::toUInt() const { - return d->m_uint; + return d->data->m_uint; } long long MP4::Item::toLongLong() const { - return d->m_longlong; + return d->data->m_longlong; } MP4::Item::IntPair MP4::Item::toIntPair() const { - return d->m_intPair; + return d->data->m_intPair; } StringList MP4::Item::toStringList() const { - return d->m_stringList; + return d->data->m_stringList; } ByteVectorList MP4::Item::toByteVectorList() const { - return d->m_byteVectorList; + return d->data->m_byteVectorList; } MP4::CoverArtList MP4::Item::toCoverArtList() const { - return d->m_coverArtList; + return d->data->m_coverArtList; } bool MP4::Item::isValid() const { - return d->valid; + return d->data->valid; +} + +String MP4::Item::toString() const { + + StringList desc; + switch (d->data->type) { + case TypeBool: + return d->data->m_bool ? "true" : "false"; + case TypeInt: + return Utils::formatString("%d", d->data->m_int); + case TypeIntPair: + return Utils::formatString("%d/%d", d->data->m_intPair.first, d->data->m_intPair.second); + case TypeByte: + return Utils::formatString("%d", d->data->m_byte); + case TypeUInt: + return Utils::formatString("%u", d->data->m_uint); + case TypeLongLong: + return Utils::formatString("%lld", d->data->m_longlong); + case TypeStringList: + return d->data->m_stringList.toString(" / "); + case TypeByteVectorList: + for (size_t i = 0; i < d->data->m_byteVectorList.size(); i++) { + desc.append(Utils::formatString( + "[%d bytes of data]", static_cast(d->data->m_byteVectorList[i].size()))); + } + return desc.toString(", "); + case TypeCoverArtList: + for (size_t i = 0; i < d->data->m_coverArtList.size(); i++) { + desc.append(Utils::formatString("[%d bytes of data]", static_cast(d->data->m_coverArtList[i].data().size()))); + } + return desc.toString(", "); + case TypeUndefined: + return "[unknown]"; + } + return String(); + } diff --git a/3rdparty/taglib/mp4/mp4item.h b/3rdparty/taglib/mp4/mp4item.h index 4be0b83a0..94bcc0818 100644 --- a/3rdparty/taglib/mp4/mp4item.h +++ b/3rdparty/taglib/mp4/mp4item.h @@ -40,6 +40,19 @@ class TAGLIB_EXPORT Item { int first, second; }; + enum ItemType { + TypeUndefined = 0, + TypeBool, + TypeInt, + TypeIntPair, + TypeByte, + TypeUInt, + TypeLongLong, + TypeStringList, + TypeByteVectorList, + TypeCoverArtList, + }; + explicit Item(); Item(const Item &item); @@ -78,8 +91,12 @@ class TAGLIB_EXPORT Item { ByteVectorList toByteVectorList() const; CoverArtList toCoverArtList() const; + ItemType type() const; + bool isValid() const; + String toString() const; + private: class ItemPrivate; ItemPrivate *d; diff --git a/3rdparty/taglib/mp4/mp4properties.cpp b/3rdparty/taglib/mp4/mp4properties.cpp index fbb464ca0..1a55eabc8 100644 --- a/3rdparty/taglib/mp4/mp4properties.cpp +++ b/3rdparty/taglib/mp4/mp4properties.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tstring.h" #include "mp4file.h" #include "mp4atom.h" #include "mp4properties.h" @@ -33,13 +33,13 @@ using namespace Strawberry_TagLib::TagLib; class MP4::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - channels(0), - bitsPerSample(0), - encrypted(false), - codec(MP4::AudioProperties::Unknown) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + bitsPerSample(0), + encrypted(false), + codec(MP4::AudioProperties::Unknown) {} int length; int bitrate; @@ -54,7 +54,7 @@ class MP4::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -MP4::AudioProperties::AudioProperties(File *file, MP4::Atoms *atoms, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +MP4::AudioProperties::AudioProperties(File *file, MP4::Atoms *atoms, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file, atoms); } @@ -95,6 +95,26 @@ MP4::AudioProperties::codec() const { return d->codec; } +String MP4::AudioProperties::toString() const { + + String format; + if (d->codec == AAC) { + format = "AAC"; + } + else if (d->codec == ALAC) { + format = "ALAC"; + } + else { + format = "Unknown"; + } + StringList desc; + desc.append("MPEG-4 audio (" + format + ")"); + desc.append(String::number(lengthInSeconds()) + " seconds"); + desc.append(String::number(bitrate()) + " kbps"); + return desc.toString(", "); + +} + //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// @@ -147,16 +167,16 @@ void MP4::AudioProperties::read(File *file, Atoms *atoms) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } - unit = data.toUInt(28U); - length = data.toLongLong(32U); + unit = data.toUInt32BE(28); + length = data.toInt64BE(32); } else { if (data.size() < 24 + 8) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } - unit = data.toUInt(20U); - length = data.toUInt(24U); + unit = data.toUInt32BE(20); + length = data.toUInt32BE(24); } if (unit > 0 && length > 0) d->length = static_cast(length * 1000.0 / unit + 0.5); @@ -170,9 +190,9 @@ void MP4::AudioProperties::read(File *file, Atoms *atoms) { data = file->readBlock(atom->length); if (data.containsAt("mp4a", 20)) { d->codec = AAC; - d->channels = data.toShort(40U); - d->bitsPerSample = data.toShort(42U); - d->sampleRate = data.toUInt(46U); + d->channels = data.toUInt16BE(40); + d->bitsPerSample = data.toUInt16BE(42); + d->sampleRate = data.toUInt32BE(46); if (data.containsAt("esds", 56) && data[64] == 0x03) { unsigned int pos = 65; if (data.containsAt("\x80\x80\x80", pos)) { @@ -185,7 +205,7 @@ void MP4::AudioProperties::read(File *file, Atoms *atoms) { pos += 3; } pos += 10; - d->bitrate = static_cast((data.toUInt(pos) + 500) / 1000.0 + 0.5); + d->bitrate = static_cast((data.toUInt32BE(pos) + 500) / 1000.0 + 0.5); } } } @@ -194,8 +214,8 @@ void MP4::AudioProperties::read(File *file, Atoms *atoms) { d->codec = ALAC; d->bitsPerSample = data.at(69); d->channels = data.at(73); - d->bitrate = static_cast(data.toUInt(80U) / 1000.0 + 0.5); - d->sampleRate = data.toUInt(84U); + d->bitrate = static_cast(data.toUInt32BE(80) / 1000.0 + 0.5); + d->sampleRate = data.toUInt32BE(84); } } diff --git a/3rdparty/taglib/mp4/mp4properties.h b/3rdparty/taglib/mp4/mp4properties.h index c2d145b93..5f885ffc4 100644 --- a/3rdparty/taglib/mp4/mp4properties.h +++ b/3rdparty/taglib/mp4/mp4properties.h @@ -46,36 +46,36 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro }; explicit AudioProperties(File *file, Atoms *atoms, ReadStyle style = Average); - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -92,6 +92,8 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro */ Codec codec() const; + String toString() const override; + private: void read(File *file, Atoms *atoms); diff --git a/3rdparty/taglib/mp4/mp4tag.cpp b/3rdparty/taglib/mp4/mp4tag.cpp index 81ea1cbdf..bff8229a2 100644 --- a/3rdparty/taglib/mp4/mp4tag.cpp +++ b/3rdparty/taglib/mp4/mp4tag.cpp @@ -23,9 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tdebug.h" +#include "tstring.h" +#include "tpicturemap.h" +#include "tpropertymap.h" #include "mp4atom.h" #include "mp4tag.h" #include "id3v1genres.h" @@ -34,7 +35,7 @@ using namespace Strawberry_TagLib::TagLib; class MP4::Tag::TagPrivate { public: - TagPrivate() : file(nullptr), atoms(nullptr) {} + explicit TagPrivate() : file(nullptr), atoms(nullptr) {} Strawberry_TagLib::TagLib::File *file; Atoms *atoms; @@ -78,7 +79,7 @@ MP4::Tag::Tag(Strawberry_TagLib::TagLib::File *file, MP4::Atoms *atoms) : d(new addItem(atom->name, StringList(String(val.data, String::UTF8))); } else { - addItem(atom->name, static_cast((val.data.toShort()))); + addItem(atom->name, static_cast((val.data.toUInt16LE(0)))); } } } @@ -117,16 +118,16 @@ MP4::AtomDataList MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, AtomDataList result; ByteVector data = d->file->readBlock(atom->length - 8); int i = 0; - unsigned int pos = 0; + size_t pos = 0; while (pos < data.size()) { - const int length = static_cast(data.toUInt(pos)); + const int length = static_cast(data.toUInt32BE(pos)); if (length < 12) { debug("MP4: Too short atom"); return result; } const ByteVector name = data.mid(pos + 4, 4); - const int flags = static_cast(data.toUInt(pos + 8)); + const int flags = static_cast(data.toUInt32BE(pos + 8)); if (freeForm && i < 2) { if (i == 0 && name != "mean") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); @@ -169,7 +170,7 @@ void MP4::Tag::parseInt(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if (!data.isEmpty()) { - addItem(atom->name, static_cast(data[0].toShort())); + addItem(atom->name, (int)data[0].toInt16BE(0)); } } @@ -178,7 +179,7 @@ void MP4::Tag::parseUInt(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if (!data.isEmpty()) { - addItem(atom->name, data[0].toUInt()); + addItem(atom->name, data[0].toUInt32BE(0)); } } @@ -187,7 +188,7 @@ void MP4::Tag::parseLongLong(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if (!data.isEmpty()) { - addItem(atom->name, data[0].toLongLong()); + addItem(atom->name, data[0].toInt64BE(0)); } } @@ -205,7 +206,7 @@ void MP4::Tag::parseGnre(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if (!data.isEmpty()) { - int idx = static_cast(data[0].toShort()); + int idx = static_cast(data[0].toInt16BE(0)); if (idx > 0) { addItem("\251gen", StringList(ID3v1::genre(idx - 1))); } @@ -217,8 +218,8 @@ void MP4::Tag::parseIntPair(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if (!data.isEmpty()) { - const int a = data[0].toShort(2U); - const int b = data[0].toShort(4U); + const int a = data[0].toInt16BE(2); + const int b = data[0].toInt16BE(4); addItem(atom->name, MP4::Item(a, b)); } @@ -294,7 +295,7 @@ void MP4::Tag::parseCovr(const MP4::Atom *atom) { ByteVector data = d->file->readBlock(atom->length - 8); unsigned int pos = 0; while (pos < data.size()) { - const int length = static_cast(data.toUInt(pos)); + const int length = static_cast(data.toUInt32BE(pos)); if (length < 12) { debug("MP4: Too short atom"); break; @@ -302,7 +303,7 @@ void MP4::Tag::parseCovr(const MP4::Atom *atom) { } const ByteVector name = data.mid(pos + 4, 4); - const int flags = static_cast(data.toUInt(pos + 8)); + const int flags = static_cast(data.toUInt32BE(pos + 8)); if (name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); break; @@ -332,14 +333,14 @@ ByteVector MP4::Tag::padIlst(const ByteVector &data, int length) const { } ByteVector MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const { - return ByteVector::fromUInt(data.size() + 8) + name + data; + return ByteVector::fromUInt32BE(data.size() + 8) + name + data; } ByteVector MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const { ByteVector result; for (ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) { - result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + *it)); + result.append(renderAtom("data", ByteVector::fromUInt32BE(flags) + ByteVector(4, '\0') + *it)); } return renderAtom(name, result); @@ -356,7 +357,7 @@ ByteVector MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) c ByteVector MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const { ByteVectorList data; - data.append(ByteVector::fromShort(item.toInt())); + data.append(ByteVector::fromUInt16BE(item.toInt())); return renderData(name, TypeInteger, data); } @@ -364,7 +365,7 @@ ByteVector MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) co ByteVector MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const { ByteVectorList data; - data.append(ByteVector::fromUInt(item.toUInt())); + data.append(ByteVector::fromUInt32BE(item.toUInt())); return renderData(name, TypeInteger, data); } @@ -372,7 +373,7 @@ ByteVector MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) c ByteVector MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const { ByteVectorList data; - data.append(ByteVector::fromLongLong(item.toLongLong())); + data.append(ByteVector::fromUInt64BE(item.toLongLong())); return renderData(name, TypeInteger, data); } @@ -389,8 +390,8 @@ ByteVector MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item ByteVectorList data; data.append(ByteVector(2, '\0') + - ByteVector::fromShort(item.toIntPair().first) + - ByteVector::fromShort(item.toIntPair().second) + + ByteVector::fromUInt16BE(item.toIntPair().first) + + ByteVector::fromUInt16BE(item.toIntPair().second) + ByteVector(2, '\0')); return renderData(name, TypeImplicit, data); @@ -400,8 +401,8 @@ ByteVector MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4:: ByteVectorList data; data.append(ByteVector(2, '\0') + - ByteVector::fromShort(item.toIntPair().first) + - ByteVector::fromShort(item.toIntPair().second)); + ByteVector::fromUInt16BE(item.toIntPair().first) + + ByteVector::fromUInt16BE(item.toIntPair().second)); return renderData(name, TypeImplicit, data); } @@ -422,7 +423,7 @@ ByteVector MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) c ByteVector data; MP4::CoverArtList value = item.toCoverArtList(); for (MP4::CoverArtList::ConstIterator it = value.begin(); it != value.end(); ++it) { - data.append(renderAtom("data", ByteVector::fromUInt(it->format()) + ByteVector(4, '\0') + it->data())); + data.append(renderAtom("data", ByteVector::fromUInt32BE(it->format()) + ByteVector(4, '\0') + it->data())); } return renderAtom(name, data); @@ -436,8 +437,8 @@ ByteVector MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) c return ByteVector(); } ByteVector data; - data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8))); - data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8))); + data.append(renderAtom("mean", ByteVector::fromUInt32BE(0) + header[1].data(String::UTF8))); + data.append(renderAtom("name", ByteVector::fromUInt32BE(0) + header[2].data(String::UTF8))); AtomDataType type = item.atomDataType(); if (type == TypeUndefined) { if (!item.toStringList().isEmpty()) { @@ -450,13 +451,13 @@ ByteVector MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) c if (type == TypeUTF8) { StringList value = item.toStringList(); for (StringList::ConstIterator it = value.begin(); it != value.end(); ++it) { - data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + it->data(String::UTF8))); + data.append(renderAtom("data", ByteVector::fromUInt32BE(type) + ByteVector(4, '\0') + it->data(String::UTF8))); } } else { ByteVectorList value = item.toByteVectorList(); for (ByteVectorList::ConstIterator it = value.begin(); it != value.end(); ++it) { - data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + *it)); + data.append(renderAtom("data", ByteVector::fromUInt32BE(type) + ByteVector(4, '\0') + *it)); } } return renderAtom("----", data); @@ -542,24 +543,24 @@ void MP4::Tag::updateParents(const AtomList &path, long delta, int ignore) { for (AtomList::ConstIterator it = path.begin(); it != itEnd; ++it) { d->file->seek((*it)->offset); - long size = d->file->readBlock(4).toUInt(); + long size = d->file->readBlock(4).toUInt32BE(0); // 64-bit if (size == 1) { d->file->seek(4, File::Current); // Skip name - long long longSize = d->file->readBlock(8).toLongLong(); + long long longSize = d->file->readBlock(8).toInt64BE(0); // Seek the offset of the 64-bit size d->file->seek((*it)->offset + 8); - d->file->writeBlock(ByteVector::fromLongLong(longSize + delta)); + d->file->writeBlock(ByteVector::fromUInt64BE(longSize + delta)); } // 32-bit else { d->file->seek((*it)->offset); - d->file->writeBlock(ByteVector::fromUInt(size + delta)); + d->file->writeBlock(ByteVector::fromUInt32BE(size + delta)); } } } -void MP4::Tag::updateOffsets(long delta, long offset) { +void MP4::Tag::updateOffsets(long delta, long long offset) { MP4::Atom *moov = d->atoms->find("moov"); if (moov) { @@ -571,15 +572,15 @@ void MP4::Tag::updateOffsets(long delta, long offset) { } d->file->seek(atom->offset + 12); ByteVector data = d->file->readBlock(atom->length - 12); - unsigned int count = data.toUInt(); + unsigned int count = data.toUInt32BE(0); d->file->seek(atom->offset + 16); - unsigned int pos = 4; + size_t pos = 4; while (count--) { - long o = static_cast(data.toUInt(pos)); + long o = data.toUInt32BE(pos); if (o > offset) { o += delta; } - d->file->writeBlock(ByteVector::fromUInt(o)); + d->file->writeBlock(ByteVector::fromUInt32BE(o)); pos += 4; } } @@ -592,15 +593,15 @@ void MP4::Tag::updateOffsets(long delta, long offset) { } d->file->seek(atom->offset + 12); ByteVector data = d->file->readBlock(atom->length - 12); - unsigned int count = data.toUInt(); + unsigned int count = data.toUInt32BE(0); d->file->seek(atom->offset + 16); - unsigned int pos = 4; + size_t pos = 4; while (count--) { - long long o = data.toLongLong(pos); + long long o = data.toInt64BE(pos); if (o > offset) { o += delta; } - d->file->writeBlock(ByteVector::fromLongLong(o)); + d->file->writeBlock(ByteVector::fromUInt64BE(o)); pos += 8; } } @@ -616,14 +617,14 @@ void MP4::Tag::updateOffsets(long delta, long offset) { } d->file->seek(atom->offset + 9); ByteVector data = d->file->readBlock(atom->length - 9); - const unsigned int flags = data.toUInt(0, 3, true); + const unsigned int flags = data.toUInt24BE(0); if (flags & 1) { - long long o = data.toLongLong(7U); + long long o = data.toInt64BE(7); if (o > offset) { o += delta; } d->file->seek(atom->offset + 16); - d->file->writeBlock(ByteVector::fromLongLong(o)); + d->file->writeBlock(ByteVector::fromUInt64BE(o)); } } } @@ -640,7 +641,7 @@ void MP4::Tag::saveNew(ByteVector data) { data = renderAtom("udta", data); } - long offset = path.back()->offset + 8; + long long offset = path.back()->offset + 8; d->file->insert(data, offset, 0); updateParents(path, data.size()); @@ -658,8 +659,8 @@ void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) { AtomList::ConstIterator it = path.end(); MP4::Atom *ilst = *(--it); - long offset = ilst->offset; - long length = ilst->length; + long long offset = ilst->offset; + long long length = ilst->length; MP4::Atom *meta = *(--it); AtomList::ConstIterator index = meta->children.find(ilst); @@ -690,7 +691,7 @@ void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) { delta = data.size() - length; } else if (delta < 0) { - data.append(padIlst(data, -delta - 8)); + data.append(padIlst(data, 0 - delta - 8)); delta = 0; } @@ -745,6 +746,42 @@ unsigned int MP4::Tag::track() const { return 0; } +PictureMap MP4::Tag::pictures() const { + + if (!d->items.contains("covr")) + return PictureMap(); + + CoverArtList list = d->items["covr"].toCoverArtList(); + if (list.isEmpty()) + return PictureMap(); + + PictureMap map; + for (CoverArtList::ConstIterator it = list.begin(); it != list.end(); ++it) { + CoverArt art = *it; + String mime = "image/"; + switch (art.format()) { + case CoverArt::BMP: + mime.append("bmp"); + break; + case CoverArt::JPEG: + mime.append("jpeg"); + break; + case CoverArt::GIF: + mime.append("gif"); + break; + case CoverArt::PNG: + mime.append("png"); + break; + case CoverArt::Unknown: + break; + } + Picture picture(art.data(), Picture::Other, mime); + map.insert(picture); + } + return PictureMap(map); + +} + void MP4::Tag::setTitle(const String &value) { d->items["\251nam"] = StringList(value); } @@ -787,6 +824,35 @@ void MP4::Tag::setTrack(unsigned int value) { } +void MP4::Tag::setPictures(const PictureMap &l) { + + CoverArtList list; + for (PictureMap::ConstIterator pictureMapIt = l.begin(); pictureMapIt != l.end(); ++pictureMapIt) { + PictureList pictures = pictureMapIt->second; + for (PictureList::ConstIterator pictureListIt = pictures.begin(); pictureListIt != pictures.end(); ++pictureListIt) { + Picture picture = *pictureListIt; + CoverArt::Format format; + String mime = picture.mime(); + if (String("image/") == mime) + format = CoverArt::Unknown; + else if (String("image/bmp") == mime) + format = CoverArt::BMP; + else if (String("image/png") == mime) + format = CoverArt::PNG; + else if (String("image/gif") == mime) + format = CoverArt::GIF; + else if (String("image/jpeg") == mime) + format = CoverArt::JPEG; + else + format = CoverArt::Unknown; + CoverArt art(format, picture.data()); + list.append(art); + } + } + d->items["covr"] = list; + +} + bool MP4::Tag::isEmpty() const { return d->items.isEmpty(); } @@ -811,6 +877,16 @@ bool MP4::Tag::contains(const String &key) const { return d->items.contains(key); } +String MP4::Tag::toString() const { + + StringList desc; + for (MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) { + desc.append(i->first + "=" + i->second.toString()); + } + return desc.toString("\n"); + +} + namespace { const char *keyTranslation[][2] = { { "\251nam", "TITLE" }, diff --git a/3rdparty/taglib/mp4/mp4tag.h b/3rdparty/taglib/mp4/mp4tag.h index 0089d6ef9..cf1c063bf 100644 --- a/3rdparty/taglib/mp4/mp4tag.h +++ b/3rdparty/taglib/mp4/mp4tag.h @@ -40,31 +40,34 @@ namespace TagLib { namespace MP4 { typedef Strawberry_TagLib::TagLib::Map ItemMap; +typedef Strawberry_TagLib::TagLib::Map ItemListMap; class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { public: explicit Tag(); explicit Tag(Strawberry_TagLib::TagLib::File *file, Atoms *atoms); - virtual ~Tag(); + ~Tag() override; bool save(); - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; + PictureMap pictures() const override; - 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); + void setTitle(const String &value) override; + void setArtist(const String &value) override; + void setAlbum(const String &value) override; + void setComment(const String &value) override; + void setGenre(const String &value) override; + void setYear(unsigned int value) override; + void setTrack(unsigned int value) override; + void setPictures(const PictureMap &l) override; - virtual bool isEmpty() const; + bool isEmpty() const override; /*! * Returns a string-keyed map of the MP4::Items for this tag. */ @@ -90,9 +93,11 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { */ bool contains(const String &key) const; - PropertyMap properties() const; - void removeUnsupportedProperties(const StringList &props); - PropertyMap setProperties(const PropertyMap &props); + String toString() const override; + + PropertyMap properties() const override; + void removeUnsupportedProperties(const StringList &props) override; + PropertyMap setProperties(const PropertyMap &props) override; private: AtomDataList parseData2(const Atom *atom, int expectedFlags = -1, bool freeForm = false); @@ -123,7 +128,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { ByteVector renderCovr(const ByteVector &name, const Item &item) const; void updateParents(const AtomList &path, long delta, int ignore = 0); - void updateOffsets(long delta, long offset); + void updateOffsets(long delta, long long offset); void saveNew(ByteVector data); void saveExisting(ByteVector data, const AtomList &path); diff --git a/3rdparty/taglib/mpc/mpcfile.cpp b/3rdparty/taglib/mpc/mpcfile.cpp index a4f1ec25c..d1fd6b773 100644 --- a/3rdparty/taglib/mpc/mpcfile.cpp +++ b/3rdparty/taglib/mpc/mpcfile.cpp @@ -23,12 +23,14 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include +#include + +#include "tbytevector.h" +#include "tstring.h" +#include "tagunion.h" +#include "tdebug.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "mpcfile.h" #include "id3v1tag.h" @@ -45,31 +47,24 @@ enum { MPCAPEIndex = 0, class MPC::File::FilePrivate { public: - FilePrivate() : APELocation(-1), - APESize(0), - ID3v1Location(-1), - ID3v2Header(nullptr), - ID3v2Location(-1), - ID3v2Size(0), - properties(nullptr) {} + explicit FilePrivate() : APELocation(-1), + APESize(0), + ID3v1Location(-1), + ID3v2Location(-1), + ID3v2Size(0) {} - ~FilePrivate() { - delete ID3v2Header; - delete properties; - } + long long APELocation; + long long APESize; - long APELocation; - long APESize; + long long ID3v1Location; - long ID3v1Location; + std::unique_ptr ID3v2Header; + long long ID3v2Location; + long long ID3v2Size; - ID3v2::Header *ID3v2Header; - long ID3v2Location; - long ID3v2Size; + DoubleTagUnion tag; - TagUnion tag; - - AudioProperties *properties; + std::unique_ptr properties; }; //////////////////////////////////////////////////////////////////////////////// @@ -112,14 +107,6 @@ Strawberry_TagLib::TagLib::Tag *MPC::File::tag() const { return &d->tag; } -PropertyMap MPC::File::properties() const { - return d->tag.properties(); -} - -void MPC::File::removeUnsupportedProperties(const StringList &properties) { - d->tag.removeUnsupportedProperties(properties); -} - PropertyMap MPC::File::setProperties(const PropertyMap &properties) { if (ID3v1Tag()) ID3v1Tag()->setProperties(properties); @@ -128,7 +115,7 @@ PropertyMap MPC::File::setProperties(const PropertyMap &properties) { } MPC::AudioProperties *MPC::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool MPC::File::save() { @@ -238,11 +225,8 @@ void MPC::File::strip(int tags) { if (!ID3v1Tag()) APETag(true); - if (tags & ID3v2) { - delete d->ID3v2Header; - d->ID3v2Header = nullptr; - } - + if (tags & ID3v2) + d->ID3v2Header.reset(); } bool MPC::File::hasID3v1Tag() const { @@ -265,7 +249,7 @@ void MPC::File::read(bool readProperties) { if (d->ID3v2Location >= 0) { seek(d->ID3v2Location); - d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); + d->ID3v2Header.reset(new ID3v2::Header(readBlock(ID3v2::Header::size()))); d->ID3v2Size = d->ID3v2Header->completeTagSize(); } @@ -293,7 +277,7 @@ void MPC::File::read(bool readProperties) { if (readProperties) { - long streamLength; + long long streamLength; if (d->APELocation >= 0) streamLength = d->APELocation; @@ -310,7 +294,7 @@ void MPC::File::read(bool readProperties) { seek(0); } - d->properties = new AudioProperties(this, streamLength); + d->properties.reset(new AudioProperties(this, streamLength)); } } diff --git a/3rdparty/taglib/mpc/mpcfile.h b/3rdparty/taglib/mpc/mpcfile.h index 39d3437f6..7b36c50ec 100644 --- a/3rdparty/taglib/mpc/mpcfile.h +++ b/3rdparty/taglib/mpc/mpcfile.h @@ -104,41 +104,33 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. * This will be an APE tag, an ID3v1 tag or a combination of the two. */ - virtual Strawberry_TagLib::TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both an APE and an ID3v1 tag, only the APE tag will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); + Strawberry_TagLib::TagLib::Tag *tag() const override; /*! * Implements the unified property interface -- import function. * Affects only the APEv2 tag which will be created if necessary. * If an ID3v1 tag exists, it will be updated as well. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; /*! * Returns the MPC::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Saves the file. * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Returns a pointer to the ID3v1 tag of the file. @@ -205,7 +197,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/mpc/mpcproperties.cpp b/3rdparty/taglib/mpc/mpcproperties.cpp index 4b2d8f746..6ff3cff55 100644 --- a/3rdparty/taglib/mpc/mpcproperties.cpp +++ b/3rdparty/taglib/mpc/mpcproperties.cpp @@ -23,29 +23,35 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include + #include #include +#include "tstring.h" +#include "tdebug.h" + #include "mpcproperties.h" #include "mpcfile.h" using namespace Strawberry_TagLib::TagLib; +namespace { +const unsigned int HeaderSize = 56; +} + class MPC::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : version(0), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - totalFrames(0), - sampleFrames(0), - trackGain(0), - trackPeak(0), - albumGain(0), - albumPeak(0) {} + explicit AudioPropertiesPrivate() : version(0), + length(0), + bitrate(0), + sampleRate(0), + channels(0), + totalFrames(0), + sampleFrames(0), + trackGain(0), + trackPeak(0), + albumGain(0), + albumPeak(0) {} int version; int length; @@ -54,21 +60,17 @@ class MPC::AudioProperties::AudioPropertiesPrivate { int channels; unsigned int totalFrames; unsigned int sampleFrames; - int trackGain; - int trackPeak; - int albumGain; - int albumPeak; + unsigned int trackGain; + unsigned int trackPeak; + unsigned int albumGain; + unsigned int albumPeak; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -MPC::AudioProperties::AudioProperties(const ByteVector &data, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { - readSV7(data, streamLength); -} - -MPC::AudioProperties::AudioProperties(File *file, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +MPC::AudioProperties::AudioProperties(File *file, long long streamLength, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { ByteVector magic = file->readBlock(4); if (magic == "MPCK") { @@ -77,7 +79,7 @@ MPC::AudioProperties::AudioProperties(File *file, long streamLength, ReadStyle s } else { // Musepack version 7 or older, fixed size header - readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength); + readSV7(magic + file->readBlock(HeaderSize - 4), streamLength); } } @@ -139,7 +141,7 @@ int MPC::AudioProperties::albumPeak() const { //////////////////////////////////////////////////////////////////////////////// namespace { -unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) { +unsigned long readSize(File *file, size_t &sizeLength, bool &eof) { sizeLength = 0; eof = false; @@ -164,7 +166,7 @@ unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof) { } -unsigned long readSize(const ByteVector &data, unsigned int &pos) { +unsigned long readSize(const ByteVector &data, size_t &pos) { unsigned char tmp; unsigned long size = 0; @@ -184,22 +186,22 @@ unsigned long readSize(const ByteVector &data, unsigned int &pos) { const unsigned short sftable[8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 }; } // namespace -void MPC::AudioProperties::readSV8(File *file, long streamLength) { +void MPC::AudioProperties::readSV8(File *file, long long streamLength) { bool readSH = false, readRG = false; while (!readSH && !readRG) { const ByteVector packetType = file->readBlock(2); - unsigned int packetSizeLength; + size_t packetSizeLength; bool eof; - const unsigned long packetSize = readSize(file, packetSizeLength, eof); + const size_t packetSize = readSize(file, packetSizeLength, eof); if (eof) { debug("MPC::AudioProperties::readSV8() - Reached to EOF."); break; } - const unsigned long dataSize = packetSize - 2 - packetSizeLength; + const size_t dataSize = packetSize - 2 - packetSizeLength; const ByteVector data = file->readBlock(dataSize); if (data.size() != dataSize) { @@ -218,7 +220,7 @@ void MPC::AudioProperties::readSV8(File *file, long streamLength) { readSH = true; - unsigned int pos = 4; + size_t pos = 4; d->version = data[pos]; pos += 1; d->sampleFrames = readSize(data, pos); @@ -233,7 +235,7 @@ void MPC::AudioProperties::readSV8(File *file, long streamLength) { break; } - const unsigned short flags = data.toUShort(pos, true); + const unsigned short flags = data.toUInt16BE(pos); pos += 2; d->sampleRate = sftable[(flags >> 13) & 0x07]; @@ -259,10 +261,10 @@ void MPC::AudioProperties::readSV8(File *file, long streamLength) { const int replayGainVersion = data[0]; if (replayGainVersion == 1) { - d->trackGain = data.toShort(1, true); - d->trackPeak = data.toShort(3, true); - d->albumGain = data.toShort(5, true); - d->albumPeak = data.toShort(7, true); + d->trackGain = data.toUInt16BE(1); + d->trackPeak = data.toUInt16BE(3); + d->albumGain = data.toUInt16BE(5); + d->albumPeak = data.toUInt16BE(7); } } @@ -277,25 +279,25 @@ void MPC::AudioProperties::readSV8(File *file, long streamLength) { } -void MPC::AudioProperties::readSV7(const ByteVector &data, long streamLength) { +void MPC::AudioProperties::readSV7(const ByteVector &data, long long streamLength) { if (data.startsWith("MP+")) { d->version = data[3] & 15; if (d->version < 7) return; - d->totalFrames = data.toUInt(4, false); + d->totalFrames = data.toUInt32LE(4); - const unsigned int flags = data.toUInt(8, false); + const unsigned int flags = data.toUInt32LE(8); d->sampleRate = sftable[(flags >> 16) & 0x03]; d->channels = 2; - const unsigned int gapless = data.toUInt(5, false); + const unsigned int gapless = data.toUInt32LE(5); - d->trackGain = data.toShort(14, false); - d->trackPeak = data.toUShort(12, false); - d->albumGain = data.toShort(18, false); - d->albumPeak = data.toUShort(16, false); + d->trackGain = data.toUInt16LE(14); + d->trackPeak = data.toUInt16LE(12); + d->albumGain = data.toUInt16LE(18); + d->albumPeak = data.toUInt16LE(16); // convert gain info if (d->trackGain != 0) { @@ -325,7 +327,7 @@ void MPC::AudioProperties::readSV7(const ByteVector &data, long streamLength) { d->sampleFrames = d->totalFrames * 1152 - 576; } else { - const unsigned int headerData = data.toUInt(0, false); + const unsigned int headerData = data.toUInt32LE(0); d->bitrate = (headerData >> 23) & 0x01ff; d->version = (headerData >> 11) & 0x03ff; @@ -333,9 +335,9 @@ void MPC::AudioProperties::readSV7(const ByteVector &data, long streamLength) { d->channels = 2; if (d->version >= 5) - d->totalFrames = data.toUInt(4, false); + d->totalFrames = data.toUInt32LE(4); else - d->totalFrames = data.toUShort(6, false); + d->totalFrames = data.toUInt16LE(6); d->sampleFrames = d->totalFrames * 1152 - 576; } diff --git a/3rdparty/taglib/mpc/mpcproperties.h b/3rdparty/taglib/mpc/mpcproperties.h index 79bc40978..629c62db4 100644 --- a/3rdparty/taglib/mpc/mpcproperties.h +++ b/3rdparty/taglib/mpc/mpcproperties.h @@ -36,8 +36,6 @@ namespace MPC { class File; -static const unsigned int HeaderSize = 8 * 7; - //! An implementation of audio property reading for MPC /*! @@ -46,22 +44,15 @@ static const unsigned int HeaderSize = 8 * 7; class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioProperties { public: - /*! - * Create an instance of MPC::AudioProperties with the data read from the ByteVector \a data. - * - * This constructor is deprecated. It only works for MPC version up to 7. - */ - explicit AudioProperties(const ByteVector &data, long streamLength, ReadStyle style = Average); - /*! * Create an instance of MPC::AudioProperties with the data read directly from a MPC::File. */ - explicit AudioProperties(File *file, long streamLength, ReadStyle style = Average); + explicit AudioProperties(File *file, long long streamLength, ReadStyle style = Average); /*! * Destroys this MPC::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. @@ -69,29 +60,29 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the version of the bitstream (SV4-SV8) @@ -128,11 +119,8 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int albumPeak() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - - void readSV7(const ByteVector &data, long streamLength); - void readSV8(File *file, long streamLength); + void readSV7(const ByteVector &data, long long streamLength); + void readSV8(File *file, long long streamLength); class AudioPropertiesPrivate; AudioPropertiesPrivate *d; diff --git a/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp b/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp index 5d7858d26..c734b6f1c 100644 --- a/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp +++ b/3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp @@ -23,8 +23,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tfile.h" +#include "tpicturemap.h" #include "id3v1tag.h" #include "id3v1genres.h" @@ -33,8 +34,24 @@ using namespace Strawberry_TagLib::TagLib; using namespace ID3v1; namespace { -const ID3v1::StringHandler defaultStringHandler; -const ID3v1::StringHandler *stringHandler = &defaultStringHandler; +class DefaultStringHandler : public Strawberry_TagLib::TagLib::StringHandler { + public: + explicit DefaultStringHandler() : Strawberry_TagLib::TagLib::StringHandler() {} + + String parse(const ByteVector &data) const override { + return String(data, String::Latin1).stripWhiteSpace(); + } + + ByteVector render(const String &s) const override { + if (s.isLatin1()) + return s.data(String::Latin1); + else + return ByteVector(); + } +}; + +const DefaultStringHandler defaultStringHandler; +const Strawberry_TagLib::TagLib::StringHandler *stringHandler = &defaultStringHandler; } // namespace class ID3v1::Tag::TagPrivate { @@ -45,7 +62,7 @@ class ID3v1::Tag::TagPrivate { genre(255) {} File *file; - long tagOffset; + long long tagOffset; String title; String artist; @@ -56,32 +73,13 @@ class ID3v1::Tag::TagPrivate { unsigned char genre; }; -//////////////////////////////////////////////////////////////////////////////// -// StringHandler implementation -//////////////////////////////////////////////////////////////////////////////// - -StringHandler::StringHandler() {} - -String ID3v1::StringHandler::parse(const ByteVector &data) const { - return String(data, String::Latin1).stripWhiteSpace(); -} - -ByteVector ID3v1::StringHandler::render(const String &s) const { - - if (s.isLatin1()) - return s.data(String::Latin1); - else - return ByteVector(); - -} - //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// ID3v1::Tag::Tag() : d(new TagPrivate()) {} -ID3v1::Tag::Tag(File *file, long tagOffset) : d(new TagPrivate()) { +ID3v1::Tag::Tag(File *file, long long tagOffset) : d(new TagPrivate()) { d->file = file; d->tagOffset = tagOffset; @@ -143,6 +141,10 @@ unsigned int ID3v1::Tag::track() const { return d->track; } +Strawberry_TagLib::TagLib::PictureMap ID3v1::Tag::pictures() const { + return PictureMap(); +} + void ID3v1::Tag::setTitle(const String &s) { d->title = s; } @@ -171,6 +173,8 @@ void ID3v1::Tag::setTrack(unsigned int i) { d->track = i < 256 ? i : 0; } +void ID3v1::Tag::setPictures(const PictureMap&) {} + unsigned int ID3v1::Tag::genreNumber() const { return d->genre; } @@ -179,7 +183,7 @@ void ID3v1::Tag::setGenreNumber(unsigned int i) { d->genre = i < 256 ? i : 255; } -void ID3v1::Tag::setStringHandler(const StringHandler *handler) { +void ID3v1::Tag::setStringHandler(const Strawberry_TagLib::TagLib::StringHandler *handler) { if (handler) stringHandler = handler; else diff --git a/3rdparty/taglib/mpeg/id3v1/id3v1tag.h b/3rdparty/taglib/mpeg/id3v1/id3v1tag.h index 86046121f..a282caf7d 100644 --- a/3rdparty/taglib/mpeg/id3v1/id3v1tag.h +++ b/3rdparty/taglib/mpeg/id3v1/id3v1tag.h @@ -28,6 +28,7 @@ #include "tag.h" #include "tbytevector.h" +#include "tstringhandler.h" #include "taglib_export.h" namespace Strawberry_TagLib { @@ -39,44 +40,6 @@ class File; namespace ID3v1 { -//! A abstraction for the string to data encoding in ID3v1 tags. - -/*! - * ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In practice it does not. - * TagLib by default only supports ISO-8859-1 data in ID3v1 tags. - * - * However by subclassing this class and reimplementing parse() and render() and setting your reimplementation as the default with - * ID3v1::Tag::setStringHandler() you can define how you would like these transformations to be done. - * - * \warning It is advisable not to write non-ISO-8859-1 data to ID3v1 tags. - * Please consider disabling the writing of ID3v1 tags in the case that the data is not ISO-8859-1. - * - * \see ID3v1::Tag::setStringHandler() - */ - -class TAGLIB_EXPORT StringHandler { - - public: - explicit StringHandler(); - virtual ~StringHandler() = default; - - /*! - * Decode a string from \a data. - * The default implementation assumes that \a data is an ISO-8859-1 (Latin1) character array. - */ - virtual String parse(const ByteVector &data) const; - - /*! - * Encode a ByteVector with the data from \a s. - * The default implementation assumes that \a s is an ISO-8859-1 (Latin1) string. - * If the string is does not conform to ISO-8859-1, no value is written. - * - * \warning It is recommended that you not override this method, but - * instead do not write an ID3v1 tag in the case that the data is not ISO-8859-1. - */ - virtual ByteVector render(const String &s) const; -}; - //! The main class in the ID3v1 implementation /*! @@ -106,12 +69,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { /*! * Create an ID3v1 tag and parse the data in \a file starting at \a tagOffset. */ - explicit Tag(File *file, long tagOffset); + explicit Tag(File *file, long long tagOffset); /*! * Destroys this Tag instance. */ - virtual ~Tag(); + ~Tag() override; /*! * Renders the in memory values to a ByteVector suitable for writing to the file. @@ -125,21 +88,23 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { // Reimplementations. - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; + PictureMap pictures() const override; - 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(unsigned int i); - virtual void setTrack(unsigned int i); + void setTitle(const String &s) override; + void setArtist(const String &s) override; + void setAlbum(const String &s) override; + void setComment(const String &s) override; + void setGenre(const String &s) override; + void setYear(unsigned int i) override; + void setTrack(unsigned int i) override; + void setPictures(const PictureMap&) override; /*! * Returns the genre in number. @@ -161,9 +126,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * * \note The caller is responsible for deleting the previous handler as needed after it is released. * - * \see StringHandler */ - static void setStringHandler(const StringHandler *handler); + static void setStringHandler(const Strawberry_TagLib::TagLib::StringHandler *handler); protected: /*! @@ -176,7 +140,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { void parse(const ByteVector &data); private: - explicit Tag(const Tag&); + Tag(const Tag&); Tag &operator=(const Tag&); class TagPrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp index ee9cc453a..774625a18 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp @@ -25,15 +25,15 @@ #include "attachedpictureframe.h" -#include -#include +#include "tstringlist.h" +#include "tdebug.h" using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; class AttachedPictureFrame::AttachedPictureFramePrivate { public: - AttachedPictureFramePrivate() : textEncoding(String::Latin1), type(AttachedPictureFrame::Other) {} + explicit AttachedPictureFramePrivate() : textEncoding(String::Latin1), type(AttachedPictureFrame::Other) {} String::Type textEncoding; String mimeType; @@ -114,17 +114,17 @@ void AttachedPictureFrame::parseFields(const ByteVector &data) { d->textEncoding = String::Type(data[0]); - int pos = 1; + size_t pos = 1; - d->mimeType = readStringField(data, String::Latin1, &pos); + d->mimeType = readStringField(data, String::Latin1, pos); /* Now we need at least two more bytes available */ - if (static_cast(pos) + 1 >= data.size()) { + if (pos + 1 >= data.size()) { debug("Truncated picture frame."); return; } d->type = static_cast(data[pos++]); - d->description = readStringField(data, d->textEncoding, &pos); + d->description = readStringField(data, d->textEncoding, pos); d->data = data.mid(pos); @@ -169,7 +169,7 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data) { d->textEncoding = String::Type(data[0]); - int pos = 1; + size_t pos = 1; String fixedString = String(data.mid(pos, 3), String::Latin1); pos += 3; @@ -186,7 +186,7 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data) { } d->type = static_cast(data[pos++]); - d->description = readStringField(data, d->textEncoding, &pos); + d->description = readStringField(data, d->textEncoding, pos); d->data = data.mid(pos); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.h b/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.h index edfefee0f..194c72fc9 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.h @@ -108,12 +108,12 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame { /*! * Destroys the AttahcedPictureFrame instance. */ - virtual ~AttachedPictureFrame(); + ~AttachedPictureFrame() override; /*! * Returns a string containing the description and mime-type */ - virtual String toString() const; + String toString() const override; /*! * Returns the text encoding used for the description. @@ -198,13 +198,13 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame { void setPicture(const ByteVector &p); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; class AttachedPictureFramePrivate; AttachedPictureFramePrivate *d; private: - explicit AttachedPictureFrame(const AttachedPictureFrame&); + AttachedPictureFrame(const AttachedPictureFrame&); AttachedPictureFrame &operator=(const AttachedPictureFrame&); explicit AttachedPictureFrame(const ByteVector &data, Header *h); }; @@ -212,7 +212,7 @@ class TAGLIB_EXPORT AttachedPictureFrame : public Frame { //! support for ID3v2.2 PIC frames class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame { protected: - virtual void parseFields(const ByteVector &data); + void parseFields(const ByteVector &data) override; private: explicit AttachedPictureFrameV22(const ByteVector &data, Header *h); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp index ab0f6f3f4..493e04eab 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp @@ -25,9 +25,9 @@ #include -#include -#include -#include +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "tdebug.h" #include "chapterframe.h" @@ -36,11 +36,11 @@ using namespace ID3v2; class ChapterFrame::ChapterFramePrivate { public: - ChapterFramePrivate() : tagHeader(nullptr), - startTime(0), - endTime(0), - startOffset(0), - endOffset(0) { + explicit ChapterFramePrivate() : tagHeader(nullptr), + startTime(0), + endTime(0), + startOffset(0), + endOffset(0) { embeddedFrameList.setAutoDelete(true); } @@ -224,23 +224,23 @@ ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVec void ChapterFrame::parseFields(const ByteVector &data) { - unsigned int size = data.size(); + size_t 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)."); return; } - int pos = 0; - unsigned int embPos = 0; - d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); - d->startTime = data.toUInt(pos, true); + size_t pos = 0; + size_t embPos = 0; + d->elementID = readStringField(data, String::Latin1, pos).data(String::Latin1); + d->startTime = data.toUInt32BE(pos); pos += 4; - d->endTime = data.toUInt(pos, true); + d->endTime = data.toUInt32BE(pos); pos += 4; - d->startOffset = data.toUInt(pos, true); + d->startOffset = data.toUInt32BE(pos); pos += 4; - d->endOffset = data.toUInt(pos, true); + d->endOffset = data.toUInt32BE(pos); pos += 4; size -= pos; @@ -273,10 +273,10 @@ ByteVector ChapterFrame::renderFields() const { data.append(d->elementID); data.append('\0'); - data.append(ByteVector::fromUInt(d->startTime, true)); - data.append(ByteVector::fromUInt(d->endTime, true)); - data.append(ByteVector::fromUInt(d->startOffset, true)); - data.append(ByteVector::fromUInt(d->endOffset, true)); + data.append(ByteVector::fromUInt32BE(d->startTime)); + data.append(ByteVector::fromUInt32BE(d->endTime)); + data.append(ByteVector::fromUInt32BE(d->startOffset)); + data.append(ByteVector::fromUInt32BE(d->endOffset)); FrameList l = d->embeddedFrameList; for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) data.append((*it)->render()); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h b/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h index 724c23612..e1992635a 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h @@ -64,7 +64,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame { /*! * Destroys the frame. */ - virtual ~ChapterFrame(); + ~ChapterFrame() override; /*! * Returns the element ID of the frame. @@ -201,7 +201,7 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame { */ void removeEmbeddedFrames(const ByteVector &id); - virtual String toString() const; + String toString() const override; PropertyMap asProperties() const; @@ -214,12 +214,12 @@ class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame { static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: explicit ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h); - explicit ChapterFrame(const ChapterFrame&); + ChapterFrame(const ChapterFrame&); ChapterFrame &operator=(const ChapterFrame&); class ChapterFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp index 25172f956..cf47eeaac 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp @@ -23,10 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include +#include "tbytevectorlist.h" +#include "id3v2tag.h" +#include "tdebug.h" +#include "tstringlist.h" #include "commentsframe.h" #include "tpropertymap.h" @@ -36,7 +36,7 @@ using namespace ID3v2; class CommentsFrame::CommentsFramePrivate { public: - CommentsFramePrivate() : textEncoding(String::Latin1) {} + explicit CommentsFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; ByteVector language; String description; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.h b/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.h index 6472e593b..bd3845ab4 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.h @@ -57,14 +57,14 @@ class TAGLIB_EXPORT CommentsFrame : public Frame { /*! * Destroys this CommentFrame instance. */ - virtual ~CommentsFrame(); + ~CommentsFrame() override; /*! * Returns the text of this comment. * * \see text() */ - virtual String toString() const; + String toString() const override; /*! * Returns the language encoding as a 3 byte encoding as specified by @@ -112,7 +112,7 @@ class TAGLIB_EXPORT CommentsFrame : public Frame { * * \see text() */ - virtual void setText(const String &s); + void setText(const String &s) override; /*! * Returns the text encoding that will be used in rendering this frame. @@ -154,15 +154,15 @@ class TAGLIB_EXPORT CommentsFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit CommentsFrame(const ByteVector &data, Header *h); - explicit CommentsFrame(const CommentsFrame &); + CommentsFrame(const CommentsFrame &); CommentsFrame &operator=(const CommentsFrame &); class CommentsFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp index 062bda4f5..15b26cac2 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp @@ -24,17 +24,17 @@ ***************************************************************************/ #include "eventtimingcodesframe.h" -#include -#include -#include -#include +#include "tbytevectorlist.h" +#include "id3v2tag.h" +#include "tdebug.h" +#include "tpropertymap.h" using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; class EventTimingCodesFrame::EventTimingCodesFramePrivate { public: - EventTimingCodesFramePrivate() : timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {} + explicit EventTimingCodesFramePrivate() : timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {} EventTimingCodesFrame::TimestampFormat timestampFormat; EventTimingCodesFrame::SynchedEventList synchedEvents; }; @@ -83,7 +83,7 @@ void EventTimingCodesFrame::setSynchedEvents( void EventTimingCodesFrame::parseFields(const ByteVector &data) { - const int end = data.size(); + const size_t end = data.size(); if (end < 1) { debug("An event timing codes frame must contain at least 1 byte."); return; @@ -91,11 +91,11 @@ void EventTimingCodesFrame::parseFields(const ByteVector &data) { d->timestampFormat = TimestampFormat(data[0]); - int pos = 1; + size_t pos = 1; d->synchedEvents.clear(); while (pos + 4 < end) { EventType type = static_cast(static_cast(data[pos++])); - unsigned int time = data.toUInt(pos, true); + unsigned int time = data.toUInt32BE(pos); pos += 4; d->synchedEvents.append(SynchedEvent(time, type)); } @@ -110,7 +110,7 @@ ByteVector EventTimingCodesFrame::renderFields() const { for (SynchedEventList::ConstIterator it = d->synchedEvents.begin(); it != d->synchedEvents.end(); ++it) { const SynchedEvent &entry = *it; v.append(char(entry.type)); - v.append(ByteVector::fromUInt(entry.time)); + v.append(ByteVector::fromUInt32BE(entry.time)); } return v; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h b/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h index 1991e5e57..280c8d96f 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h @@ -129,12 +129,12 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame { /*! * Destroys this EventTimingCodesFrame instance. */ - virtual ~EventTimingCodesFrame(); + ~EventTimingCodesFrame() override; /*! * Returns a null string. */ - virtual String toString() const; + String toString() const override; /*! * Returns the timestamp format. @@ -163,15 +163,15 @@ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit EventTimingCodesFrame(const ByteVector &data, Header *h); - explicit EventTimingCodesFrame(const EventTimingCodesFrame&); + EventTimingCodesFrame(const EventTimingCodesFrame&); EventTimingCodesFrame &operator=(const EventTimingCodesFrame&); class EventTimingCodesFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp index 344615a85..31671135b 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp @@ -26,8 +26,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tstringlist.h" #include "generalencapsulatedobjectframe.h" @@ -36,7 +36,7 @@ using namespace ID3v2; class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate { public: - GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {} + explicit GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; String mimeType; @@ -126,11 +126,11 @@ void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) { d->textEncoding = String::Type(data[0]); - int pos = 1; + size_t pos = 1; - d->mimeType = readStringField(data, String::Latin1, &pos); - d->fileName = readStringField(data, d->textEncoding, &pos); - d->description = readStringField(data, d->textEncoding, &pos); + d->mimeType = readStringField(data, String::Latin1, pos); + d->fileName = readStringField(data, d->textEncoding, pos); + d->description = readStringField(data, d->textEncoding, pos); d->data = data.mid(pos); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h b/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h index 7878c6747..1c850d603 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h @@ -70,12 +70,12 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame { /*! * Destroys the GeneralEncapsulatedObjectFrame instance. */ - virtual ~GeneralEncapsulatedObjectFrame(); + ~GeneralEncapsulatedObjectFrame() override; /*! * Returns a string containing the description, file name and mime-type */ - virtual String toString() const; + String toString() const override; /*! * Returns the text encoding used for the description and file name. @@ -160,12 +160,12 @@ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame { void setObject(const ByteVector &data); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: explicit GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h); - explicit GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame&); + GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame&); GeneralEncapsulatedObjectFrame &operator=(const GeneralEncapsulatedObjectFrame&); class GeneralEncapsulatedObjectFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp index 1a5800e47..68d982453 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp @@ -23,9 +23,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tdebug.h" +#include "tstringlist.h" +#include "id3v2tag.h" #include "ownershipframe.h" @@ -98,14 +98,14 @@ void OwnershipFrame::setTextEncoding(String::Type encoding) { void OwnershipFrame::parseFields(const ByteVector &data) { - int pos = 0; + size_t 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); + 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 diff --git a/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h b/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h index 9b2ac0357..46aad1ae1 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h @@ -57,14 +57,14 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame { /*! * Destroys this OwnershipFrame instance. */ - virtual ~OwnershipFrame(); + ~OwnershipFrame() override; /*! * Returns the text of this popularimeter. * * \see text() */ - virtual String toString() const; + String toString() const override; /*! * Returns the date purchased. @@ -128,15 +128,15 @@ class TAGLIB_EXPORT OwnershipFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit OwnershipFrame(const ByteVector &data, Header *h); - explicit OwnershipFrame(const OwnershipFrame&); + OwnershipFrame(const OwnershipFrame&); OwnershipFrame &operator=(const OwnershipFrame &); class OwnershipFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h b/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h index 012dd6e18..cba3f7f91 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h @@ -49,25 +49,25 @@ class TAGLIB_EXPORT PodcastFrame : public Frame { /*! * Destroys this PodcastFrame instance. */ - virtual ~PodcastFrame(); + ~PodcastFrame() override; /*! * Returns a null string. */ - virtual String toString() const; + String toString() const override; protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit PodcastFrame(const ByteVector &data, Header *h); - explicit PodcastFrame(const PodcastFrame &); + PodcastFrame(const PodcastFrame &); PodcastFrame &operator=(const PodcastFrame &); class PodcastFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp index b7494b3a7..fa61f8ea4 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp @@ -23,7 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include +#include "tdebug.h" #include "popularimeterframe.h" @@ -32,7 +32,7 @@ using namespace ID3v2; class PopularimeterFrame::PopularimeterFramePrivate { public: - PopularimeterFramePrivate() : rating(0), counter(0) {} + explicit PopularimeterFramePrivate() : rating(0), counter(0) {} String email; int rating; unsigned int counter; @@ -86,16 +86,17 @@ void PopularimeterFrame::setCounter(unsigned int counter) { void PopularimeterFrame::parseFields(const ByteVector &data) { - int pos = 0, size = int(data.size()); + size_t pos = 0; + const size_t size = data.size(); - d->email = readStringField(data, String::Latin1, &pos); + d->email = readStringField(data, String::Latin1, pos); d->rating = 0; d->counter = 0; if (pos < size) { d->rating = static_cast(data[pos++]); if (pos < size) { - d->counter = data.toUInt(static_cast(pos)); + d->counter = data.toUInt32BE(pos); } } @@ -108,7 +109,7 @@ ByteVector PopularimeterFrame::renderFields() const { data.append(d->email.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); data.append(char(d->rating)); - data.append(ByteVector::fromUInt(d->counter)); + data.append(ByteVector::fromUInt32BE(d->counter)); return data; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h b/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h index 287098de7..4b69c0e7c 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h @@ -57,14 +57,14 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame { /*! * Destroys this PopularimeterFrame instance. */ - virtual ~PopularimeterFrame(); + ~PopularimeterFrame() override; /*! * Returns the text of this popularimeter. * * \see text() */ - virtual String toString() const; + String toString() const override; /*! * Returns the email. @@ -111,15 +111,15 @@ class TAGLIB_EXPORT PopularimeterFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit PopularimeterFrame(const ByteVector &data, Header *h); - explicit PopularimeterFrame(const PopularimeterFrame&); + PopularimeterFrame(const PopularimeterFrame&); PopularimeterFrame &operator=(const PopularimeterFrame&); class PopularimeterFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp index 4abfe123a..ec8159d21 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp @@ -24,9 +24,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tbytevectorlist.h" +#include "id3v2tag.h" +#include "tdebug.h" #include "privateframe.h" @@ -87,8 +87,7 @@ void PrivateFrame::parseFields(const ByteVector &data) { // Owner identifier is assumed to be Latin1 - const int byteAlign = 1; - const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign); + const size_t endOfOwner = data.find(textDelimiter(String::Latin1), 0, 1); d->owner = String(data.mid(0, endOfOwner)); d->data = data.mid(endOfOwner + 1); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/privateframe.h b/3rdparty/taglib/mpeg/id3v2/frames/privateframe.h index 216d14f59..5fb852d0f 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/privateframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/privateframe.h @@ -55,14 +55,14 @@ class TAGLIB_EXPORT PrivateFrame : public Frame { /*! * Destroys this private frame instance. */ - virtual ~PrivateFrame(); + ~PrivateFrame() override; /*! * Returns the text of this private frame, currently just the owner. * * \see text() */ - virtual String toString() const; + String toString() const override; /*! * \return The owner of the private frame. @@ -89,8 +89,8 @@ class TAGLIB_EXPORT PrivateFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! @@ -98,7 +98,7 @@ class TAGLIB_EXPORT PrivateFrame : public Frame { */ explicit PrivateFrame(const ByteVector &data, Header *h); - explicit PrivateFrame(const PrivateFrame&); + PrivateFrame(const PrivateFrame&); PrivateFrame &operator=(const PrivateFrame&); class PrivateFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp index 9eb104f37..a6075e7d7 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp @@ -23,21 +23,23 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tmap.h" #include "relativevolumeframe.h" using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; +namespace { struct ChannelData { - ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} + explicit ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} RelativeVolumeFrame::ChannelType channelType; short volumeAdjustment; RelativeVolumeFrame::PeakVolume peakVolume; }; +} // namespace class RelativeVolumeFrame::RelativeVolumeFramePrivate { public: @@ -79,50 +81,26 @@ short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const { return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0; } -short RelativeVolumeFrame::volumeAdjustmentIndex() const { - return volumeAdjustmentIndex(MasterVolume); -} - void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type) { d->channels[type].volumeAdjustment = index; } -void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index) { - setVolumeAdjustmentIndex(index, MasterVolume); -} - float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const { return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0; } -float RelativeVolumeFrame::volumeAdjustment() const { - return volumeAdjustment(MasterVolume); -} - void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type) { d->channels[type].volumeAdjustment = short(adjustment * float(512)); } -void RelativeVolumeFrame::setVolumeAdjustment(float adjustment) { - setVolumeAdjustment(adjustment, MasterVolume); -} - RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const { return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume(); } -RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const { - return peakVolume(MasterVolume); -} - void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type) { d->channels[type].peakVolume = peak; } -void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak) { - setPeakVolume(peak, MasterVolume); -} - String RelativeVolumeFrame::identification() const { return d->identification; } @@ -137,19 +115,19 @@ void RelativeVolumeFrame::setIdentification(const String &s) { void RelativeVolumeFrame::parseFields(const ByteVector &data) { - int pos = 0; - d->identification = readStringField(data, String::Latin1, &pos); + size_t pos = 0; + d->identification = readStringField(data, String::Latin1, pos); // Each channel is at least 4 bytes. - while (pos <= static_cast(data.size()) - 4) { + while (pos + 4 <= data.size()) { ChannelType type = ChannelType(data[pos]); pos += 1; ChannelData &channel = d->channels[type]; - channel.volumeAdjustment = data.toShort(static_cast(pos)); + channel.volumeAdjustment = data.toInt16BE(pos); pos += 2; channel.peakVolume.bitsRepresentingPeak = data[pos]; @@ -176,7 +154,7 @@ ByteVector RelativeVolumeFrame::renderFields() const { const ChannelData &channel = (*it).second; data.append(char(type)); - data.append(ByteVector::fromShort(channel.volumeAdjustment)); + data.append(ByteVector::fromUInt16BE(channel.volumeAdjustment)); data.append(char(channel.peakVolume.bitsRepresentingPeak)); data.append(channel.peakVolume.peakVolume); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.h b/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.h index df3665f69..401f1902d 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.h @@ -105,26 +105,20 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame { /*! * Destroys the RelativeVolumeFrame instance. */ - virtual ~RelativeVolumeFrame(); + ~RelativeVolumeFrame() override; /*! * Returns the frame's identification. * * \see identification() */ - virtual String toString() const; + String toString() const override; /*! * Returns a list of channels with information currently in the frame. */ List channels() const; - /* - * There was a terrible API goof here, and while this can't be changed to the way it appears below for binary compatibility reasons, let's at least pretend that it looks clean. - */ - -#ifdef DOXYGEN - /*! * Returns the relative volume adjustment "index". * As indicated by the ID3v2 standard this is a 16-bit signed integer that reflects the decibels of adjustment when divided by 512. @@ -190,30 +184,6 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame { */ void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume); -#else - - // BIC: Combine each of the following pairs of functions (or maybe just rework this junk altogether). - - short volumeAdjustmentIndex(ChannelType type) const; - short volumeAdjustmentIndex() const; - - void setVolumeAdjustmentIndex(short index, ChannelType type); - void setVolumeAdjustmentIndex(short index); - - float volumeAdjustment(ChannelType type) const; - float volumeAdjustment() const; - - void setVolumeAdjustment(float adjustment, ChannelType type); - void setVolumeAdjustment(float adjustment); - - PeakVolume peakVolume(ChannelType type) const; - PeakVolume peakVolume() const; - - void setPeakVolume(const PeakVolume &peak, ChannelType type); - void setPeakVolume(const PeakVolume &peak); - -#endif - /*! * Returns the identification for this frame. */ @@ -226,12 +196,12 @@ class TAGLIB_EXPORT RelativeVolumeFrame : public Frame { void setIdentification(const String &s); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: explicit RelativeVolumeFrame(const ByteVector &data, Header *h); - explicit RelativeVolumeFrame(const RelativeVolumeFrame&); + RelativeVolumeFrame(const RelativeVolumeFrame&); RelativeVolumeFrame &operator=(const RelativeVolumeFrame&); class RelativeVolumeFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp index 1d9dcad7a..760461e73 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp @@ -24,19 +24,19 @@ ***************************************************************************/ #include "synchronizedlyricsframe.h" -#include -#include -#include -#include +#include "tbytevectorlist.h" +#include "id3v2tag.h" +#include "tdebug.h" +#include "tpropertymap.h" using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate { public: - SynchronizedLyricsFramePrivate() : textEncoding(String::Latin1), - timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds), - type(SynchronizedLyricsFrame::Lyrics) {} + explicit SynchronizedLyricsFramePrivate() : textEncoding(String::Latin1), + timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds), + type(SynchronizedLyricsFrame::Lyrics) {} String::Type textEncoding; ByteVector language; SynchronizedLyricsFrame::TimestampFormat timestampFormat; @@ -124,7 +124,7 @@ void SynchronizedLyricsFrame::setSynchedText( void SynchronizedLyricsFrame::parseFields(const ByteVector &data) { - const int end = data.size(); + const size_t end = data.size(); if (end < 7) { debug("A synchronized lyrics frame must contain at least 7 bytes."); return; @@ -135,9 +135,9 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) { d->timestampFormat = TimestampFormat(data[4]); d->type = Type(data[5]); - int pos = 6; + size_t pos = 6; - d->description = readStringField(data, d->textEncoding, &pos); + d->description = readStringField(data, d->textEncoding, pos); if (pos == 6) return; @@ -150,7 +150,7 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) { */ String::Type encWithEndianness = d->textEncoding; if (d->textEncoding == String::UTF16) { - unsigned short bom = data.toUShort(6, true); + unsigned short bom = data.toUInt16BE(6); if (bom == 0xfffe) { encWithEndianness = String::UTF16LE; } @@ -164,16 +164,16 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) { String::Type enc = d->textEncoding; // If a UTF16 string has no BOM, use the encoding found above. if (enc == String::UTF16 && pos + 1 < end) { - unsigned short bom = data.toUShort(pos, true); + unsigned short bom = data.toUInt16BE(pos); if (bom != 0xfffe && bom != 0xfeff) { enc = encWithEndianness; } } - String text = readStringField(data, enc, &pos); + String text = readStringField(data, enc, pos); if (pos + 4 > end) return; - unsigned int time = data.toUInt(pos, true); + unsigned int time = data.toUInt32BE(pos); pos += 4; d->synchedText.append(SynchedText(time, text)); @@ -206,7 +206,7 @@ ByteVector SynchronizedLyricsFrame::renderFields() const { const SynchedText &entry = *it; v.append(entry.text.data(encoding)); v.append(textDelimiter(encoding)); - v.append(ByteVector::fromUInt(entry.time)); + v.append(ByteVector::fromUInt32BE(entry.time)); } return v; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h b/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h index a9c06745c..3bf6684f7 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h @@ -106,14 +106,14 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame { /*! * Destroys this SynchronizedLyricsFrame instance. */ - virtual ~SynchronizedLyricsFrame(); + ~SynchronizedLyricsFrame() override; /*! * Returns the description of this synchronized lyrics frame. * * \see description() */ - virtual String toString() const; + String toString() const override; /*! * Returns the text encoding that will be used in rendering this frame. @@ -205,15 +205,15 @@ class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit SynchronizedLyricsFrame(const ByteVector &data, Header *h); - explicit SynchronizedLyricsFrame(const SynchronizedLyricsFrame&); + SynchronizedLyricsFrame(const SynchronizedLyricsFrame&); SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame&); class SynchronizedLyricsFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp index 6d7d4253c..d503b5bae 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp @@ -23,9 +23,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "tdebug.h" #include "tableofcontentsframe.h" @@ -34,7 +34,7 @@ using namespace ID3v2; class TableOfContentsFrame::TableOfContentsFramePrivate { public: - TableOfContentsFramePrivate() : tagHeader(nullptr), isTopLevel(false), isOrdered(false) { + explicit TableOfContentsFramePrivate() : tagHeader(nullptr), isTopLevel(false), isOrdered(false) { embeddedFrameList.setAutoDelete(true); } @@ -259,7 +259,7 @@ TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) void TableOfContentsFrame::parseFields(const ByteVector &data) { - unsigned int size = data.size(); + size_t 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 " @@ -267,14 +267,14 @@ void TableOfContentsFrame::parseFields(const ByteVector &data) { return; } - int pos = 0; - unsigned int embPos = 0; - d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); + size_t pos = 0; + size_t 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; unsigned int entryCount = static_cast(data.at(pos++)); for (unsigned int i = 0; i < entryCount; i++) { - ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); + ByteVector childElementID = readStringField(data, String::Latin1, pos).data(String::Latin1); d->childElements.append(childElementID); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h index eef2c6e70..bfebb4e64 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h @@ -61,7 +61,7 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame { /*! * Destroys the frame. */ - ~TableOfContentsFrame(); + ~TableOfContentsFrame() override; /*! * Returns the elementID of the frame. @@ -200,7 +200,7 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame { */ void removeEmbeddedFrames(const ByteVector &id); - virtual String toString() const; + String toString() const override; PropertyMap asProperties() const; @@ -223,12 +223,12 @@ class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame { static TableOfContentsFrame *findTopLevel(const Tag *tag); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: explicit TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h); - explicit TableOfContentsFrame(const TableOfContentsFrame&); + TableOfContentsFrame(const TableOfContentsFrame&); TableOfContentsFrame &operator=(const TableOfContentsFrame&); class TableOfContentsFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp index 89e473036..55d9e04d0 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tbytevectorlist.h" +#include "id3v2tag.h" #include "textidentificationframe.h" #include "tpropertymap.h" #include "id3v1genres.h" @@ -34,7 +34,7 @@ using namespace ID3v2; class TextIdentificationFrame::TextIdentificationFramePrivate { public: - TextIdentificationFramePrivate() : textEncoding(String::Latin1) {} + explicit TextIdentificationFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; StringList fieldList; }; @@ -159,8 +159,8 @@ PropertyMap TextIdentificationFrame::asProperties() const { for (StringList::Iterator it = values.begin(); it != values.end(); ++it) { // ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time. // Since this is unusual in other formats, the T is removed. - int tpos = it->find("T"); - if (tpos != -1) + const size_t tpos = it->find("T"); + if (tpos != String::npos()) (*it)[tpos] = ' '; } } @@ -405,7 +405,7 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, void UserTextIdentificationFrame::checkFields() { - int fields = fieldList().size(); + const size_t fields = fieldList().size(); if (fields == 0) setDescription(String()); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.h b/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.h index aaf6bf815..fdbd5f874 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.h @@ -136,7 +136,7 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame { /*! * Destroys this TextIdentificationFrame instance. */ - virtual ~TextIdentificationFrame(); + ~TextIdentificationFrame() override; /*! * Text identification frames are a list of string fields. @@ -151,8 +151,8 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame { // Reimplementations. - virtual void setText(const String &s); - virtual String toString() const; + void setText(const String &s) override; + String toString() const override; /*! * Returns the text encoding that will be used in rendering this frame. @@ -190,8 +190,8 @@ class TAGLIB_EXPORT TextIdentificationFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; /*! * The constructor used by the FrameFactory. @@ -245,7 +245,7 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame */ UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8); - virtual String toString() const; + String toString() const override; /*! * Returns the description for this frame. @@ -259,7 +259,7 @@ class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame void setDescription(const String &s); StringList fieldList() const; - void setText(const String &text); + void setText(const String &text) override; void setText(const StringList &fields); /*! diff --git a/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp index 1d65374ea..10c42d3d8 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp @@ -23,9 +23,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "tdebug.h" #include "id3v2tag.h" #include "uniquefileidentifierframe.h" @@ -112,8 +112,8 @@ void UniqueFileIdentifierFrame::parseFields(const ByteVector &data) { return; } - int pos = 0; - d->owner = readStringField(data, String::Latin1, &pos); + size_t pos = 0; + d->owner = readStringField(data, String::Latin1, pos); d->identifier = data.mid(pos); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h b/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h index 538bc021f..4ad9edea3 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h @@ -56,7 +56,7 @@ class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame { /*! * Destroys the frame. */ - ~UniqueFileIdentifierFrame(); + ~UniqueFileIdentifierFrame() override; /*! * Returns the owner for the frame; essentially this is the key for determining which identification scheme this key belongs to. @@ -87,7 +87,7 @@ class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame { */ void setIdentifier(const ByteVector &v); - virtual String toString() const; + String toString() const override; PropertyMap asProperties() const; @@ -99,11 +99,11 @@ class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame { static UniqueFileIdentifierFrame *findByOwner(const Tag *tag, const String &o); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: - explicit UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame&); + UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame&); UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame&); explicit UniqueFileIdentifierFrame(const ByteVector &data, Header *h); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.h b/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.h index a097f9b2e..6669da4f4 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.h @@ -49,10 +49,10 @@ class TAGLIB_EXPORT UnknownFrame : public Frame { friend class FrameFactory; public: - UnknownFrame(const ByteVector &data); - virtual ~UnknownFrame(); + explicit UnknownFrame(const ByteVector &data); + ~UnknownFrame() override; - virtual String toString() const; + String toString() const override; /*! * Returns the field data (everything but the header) for this frame. @@ -60,12 +60,12 @@ class TAGLIB_EXPORT UnknownFrame : public Frame { ByteVector data() const; protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: explicit UnknownFrame(const ByteVector &data, Header *h); - explicit UnknownFrame(const UnknownFrame&); + UnknownFrame(const UnknownFrame&); UnknownFrame &operator=(const UnknownFrame&); class UnknownFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp index a31a5716a..84872a83e 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp @@ -27,17 +27,17 @@ ***************************************************************************/ #include "unsynchronizedlyricsframe.h" -#include -#include -#include -#include +#include "tbytevectorlist.h" +#include "id3v2tag.h" +#include "tdebug.h" +#include "tpropertymap.h" using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate { public: - UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {} + explicit UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; ByteVector language; String description; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h b/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h index 105d3497d..473650baa 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h @@ -55,14 +55,14 @@ class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame { /*! * Destroys this UnsynchronizedLyricsFrame instance. */ - virtual ~UnsynchronizedLyricsFrame(); + ~UnsynchronizedLyricsFrame() override; /*! * Returns the text of this unsynchronized lyrics frame. * * \see text() */ - virtual String toString() const; + String toString() const override; /*! * Returns the language encoding as a 3 byte encoding as specified by @@ -111,7 +111,7 @@ class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame { * * \see text() */ - virtual void setText(const String &s); + void setText(const String &s) override; /*! * Returns the text encoding that will be used in rendering this frame. @@ -154,15 +154,15 @@ class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame { protected: // Reimplementations. - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; private: /*! * The constructor used by the FrameFactory. */ explicit UnsynchronizedLyricsFrame(const ByteVector &data, Header *h); - explicit UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame&); + UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame&); UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame&); class UnsynchronizedLyricsFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp index 09ce05dbf..a88d522f8 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp @@ -28,9 +28,9 @@ #include "urllinkframe.h" #include "id3v2tag.h" -#include -#include -#include +#include "tdebug.h" +#include "tstringlist.h" +#include "tpropertymap.h" using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; @@ -42,7 +42,7 @@ class UrlLinkFrame::UrlLinkFramePrivate { class UserUrlLinkFrame::UserUrlLinkFramePrivate { public: - UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {} + explicit UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; String description; }; @@ -179,22 +179,22 @@ void UserUrlLinkFrame::parseFields(const ByteVector &data) { return; } - int pos = 0; + size_t pos = 0; d->textEncoding = String::Type(data[0]); pos += 1; if (d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) { - int offset = data.find(textDelimiter(d->textEncoding), pos); - if (offset < pos) + const size_t offset = data.find(textDelimiter(d->textEncoding), pos); + if (offset == ByteVector::npos() || offset < pos) return; d->description = String(data.mid(pos, offset - pos), d->textEncoding); pos = offset + 1; } else { - int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2); - if (len < 0) + const size_t len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2); + if (len == ByteVector::npos()) return; d->description = String(data.mid(pos, len), d->textEncoding); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h b/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h index ac230ae3a..792e5920b 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h @@ -52,7 +52,7 @@ class TAGLIB_EXPORT UrlLinkFrame : public Frame { /*! * Destroys this UrlLinkFrame instance. */ - virtual ~UrlLinkFrame(); + ~UrlLinkFrame() override; /*! * Returns the URL. @@ -66,13 +66,13 @@ class TAGLIB_EXPORT UrlLinkFrame : public Frame { // Reimplementations. - virtual void setText(const String &s); - virtual String toString() const; + void setText(const String &s) override; + String toString() const override; PropertyMap asProperties() const; protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; /*! * The constructor used by the FrameFactory. @@ -114,11 +114,11 @@ class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame { /*! * Destroys this UserUrlLinkFrame instance. */ - virtual ~UserUrlLinkFrame(); + ~UserUrlLinkFrame() override; // Reimplementations. - virtual String toString() const; + String toString() const override; /*! * Returns the text encoding that will be used in rendering this frame. @@ -164,8 +164,8 @@ class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame { static UserUrlLinkFrame *find(Tag *tag, const String &description); protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; + void parseFields(const ByteVector &data) override; + ByteVector renderFields() const override; /*! * The constructor used by the FrameFactory. @@ -173,7 +173,7 @@ class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame { UserUrlLinkFrame(const ByteVector &data, Header *h); private: - explicit UserUrlLinkFrame(const UserUrlLinkFrame&); + UserUrlLinkFrame(const UserUrlLinkFrame&); UserUrlLinkFrame &operator=(const UserUrlLinkFrame&); class UserUrlLinkFramePrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp index ddb20753c..8b273e63c 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp @@ -31,7 +31,7 @@ using namespace ID3v2; class ExtendedHeader::ExtendedHeaderPrivate { public: - ExtendedHeaderPrivate() : size(0) {} + explicit ExtendedHeaderPrivate() : size(0) {} unsigned int size; }; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h b/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h index 714ed7e85..636832b1e 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h +++ b/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h @@ -78,7 +78,7 @@ class TAGLIB_EXPORT ExtendedHeader { void parse(const ByteVector &data); private: - explicit ExtendedHeader(const ExtendedHeader&); + ExtendedHeader(const ExtendedHeader&); ExtendedHeader &operator=(const ExtendedHeader&); class ExtendedHeaderPrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2footer.h b/3rdparty/taglib/mpeg/id3v2/id3v2footer.h index b5eef30c7..2d297fa7e 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2footer.h +++ b/3rdparty/taglib/mpeg/id3v2/id3v2footer.h @@ -68,7 +68,7 @@ class TAGLIB_EXPORT Footer { ByteVector render(const Header *header) const; private: - explicit Footer(const Footer&); + Footer(const Footer&); Footer &operator=(const Footer&); class FooterPrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp index 24032a485..880067db5 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp @@ -25,9 +25,9 @@ #include -#include -#include -#include +#include "tdebug.h" +#include "tstringlist.h" +#include "tzlib.h" #include "id3v2tag.h" #include "id3v2frame.h" @@ -46,7 +46,7 @@ using namespace ID3v2; class Frame::FramePrivate { public: - FramePrivate() : header(nullptr) {} + explicit FramePrivate() : header(nullptr) {} ~FramePrivate() { delete header; @@ -222,10 +222,10 @@ void Frame::parse(const ByteVector &data) { ByteVector Frame::fieldData(const ByteVector &frameData) const { - unsigned int headerSize = Header::size(d->header->version()); + const size_t headerSize = Header::size(d->header->version()); - unsigned int frameDataOffset = headerSize; - unsigned int frameDataLength = size(); + size_t frameDataOffset = headerSize; + size_t frameDataLength = size(); if (d->header->compression() || d->header->dataLengthIndicator()) { frameDataLength = SynchData::toUInt(frameData.mid(headerSize, 4)); @@ -250,27 +250,22 @@ ByteVector Frame::fieldData(const ByteVector &frameData) const { } -String Frame::readStringField(const ByteVector &data, String::Type encoding, int *position) { - - int start = 0; - - if (!position) - position = &start; +String Frame::readStringField(const ByteVector &data, String::Type encoding, size_t &position) { ByteVector delimiter = textDelimiter(encoding); - int end = data.find(delimiter, *position, delimiter.size()); + const size_t end = data.find(delimiter, position, delimiter.size()); - if (end < *position) + if (end == ByteVector::npos() || end < position) return String(); String str; if (encoding == String::Latin1) - str = Tag::latin1StringHandler()->parse(data.mid(*position, end - *position)); + str = Tag::latin1StringHandler()->parse(data.mid(position, end - position)); else - str = String(data.mid(*position, end - *position), encoding); + str = String(data.mid(position, end - position), encoding); - *position = end + delimiter.size(); + position = end + delimiter.size(); return str; @@ -594,7 +589,7 @@ void Frame::Header::setData(const ByteVector &data, unsigned int version) { return; } - d->frameSize = data.toUInt(3, 3, true); + d->frameSize = data.toUInt24BE(3); break; } @@ -621,7 +616,7 @@ void Frame::Header::setData(const ByteVector &data, unsigned int version) { // Set the size -- the frame size is the four bytes starting at byte four in // the frame header (structure 4) - d->frameSize = data.toUInt(4U); + d->frameSize = data.toUInt32BE(4); { // read the first byte of flags std::bitset<8> flags(data[8]); @@ -667,7 +662,7 @@ void Frame::Header::setData(const ByteVector &data, unsigned int version) { // iTunes writes v2.4 tags with v2.3-like frame sizes if (d->frameSize > 127) { if (!isValidFrameID(data.mid(d->frameSize + 10, 4))) { - unsigned int uintSize = data.toUInt(4U); + const unsigned int uintSize = data.toUInt32BE(4); if (isValidFrameID(data.mid(uintSize + 10, 4))) { d->frameSize = uintSize; } @@ -765,7 +760,7 @@ ByteVector Frame::Header::render() const { ByteVector flags(2, char(0)); // just blank for the moment ByteVector v = d->frameID + - (d->version == 3 ? ByteVector::fromUInt(d->frameSize) : SynchData::fromUInt(d->frameSize)) + + (d->version == 3 ? ByteVector::fromUInt32BE(d->frameSize) : SynchData::fromUInt(d->frameSize)) + flags; return v; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2frame.h b/3rdparty/taglib/mpeg/id3v2/id3v2frame.h index 4b7094e54..0185e8669 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2frame.h +++ b/3rdparty/taglib/mpeg/id3v2/id3v2frame.h @@ -167,7 +167,7 @@ class TAGLIB_EXPORT Frame { * * The ownership of this header will be assigned to the frame and the header will be deleted when the frame is destroyed. */ - Frame(Header *h); + explicit Frame(Header *h); /*! * Returns a pointer to the frame header. @@ -208,7 +208,7 @@ class TAGLIB_EXPORT Frame { * If \a position is passed in it is used both as the starting point and is updated to return the position just after the string that has been read. * This is useful for reading strings sequentially. */ - String readStringField(const ByteVector &data, String::Type encoding, int *position = 0); + String readStringField(const ByteVector &data, String::Type encoding, size_t &position); /*! * Checks a the list of string values to see if they can be used with the specified encoding and returns the recommended encoding. @@ -271,7 +271,7 @@ class TAGLIB_EXPORT Frame { static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, PropertyMap &tiplProperties, PropertyMap &tmclProperties); private: - explicit Frame(const Frame&); + Frame(const Frame&); Frame &operator=(const Frame&); class FramePrivate; @@ -455,7 +455,7 @@ class TAGLIB_EXPORT Frame::Header { ByteVector render() const; private: - explicit Header(const Header&); + Header(const Header&); Header &operator=(const Header&); class HeaderPrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp index 6815f359e..b7f3411e0 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tzlib.h" #include "id3v2framefactory.h" #include "id3v2synchdata.h" @@ -59,7 +59,7 @@ void updateGenre(TextIdentificationFrame *frame) { for (StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { String s = *it; - int end = s.find(")"); + size_t end = s.find(")"); if (s.startsWith("(") && end > 0) { // "(12)Genre" @@ -87,7 +87,7 @@ void updateGenre(TextIdentificationFrame *frame) { class FrameFactory::FrameFactoryPrivate { public: - FrameFactoryPrivate() : defaultEncoding(String::Latin1), useDefaultEncoding(false) {} + explicit FrameFactoryPrivate() : defaultEncoding(String::Latin1), useDefaultEncoding(false) {} String::Type defaultEncoding; bool useDefaultEncoding; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h b/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h index b73435333..ba0d943ef 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h +++ b/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h @@ -114,7 +114,7 @@ class TAGLIB_EXPORT FrameFactory { virtual bool updateFrame(Frame::Header *header) const; private: - explicit FrameFactory(const FrameFactory&); + FrameFactory(const FrameFactory&); FrameFactory &operator=(const FrameFactory&); static FrameFactory factory; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp index 8fa4d3aff..87c8dbd54 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2header.cpp @@ -26,8 +26,8 @@ #include #include -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "id3v2header.h" #include "id3v2footer.h" @@ -38,13 +38,13 @@ using namespace ID3v2; class Header::HeaderPrivate { public: - HeaderPrivate() : majorVersion(4), - revisionNumber(0), - unsynchronisation(false), - extendedHeader(false), - experimentalIndicator(false), - footerPresent(false), - tagSize(0) {} + explicit HeaderPrivate() : majorVersion(4), + revisionNumber(0), + unsynchronisation(false), + extendedHeader(false), + experimentalIndicator(false), + footerPresent(false), + tagSize(0) {} unsigned int majorVersion; unsigned int revisionNumber; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2header.h b/3rdparty/taglib/mpeg/id3v2/id3v2header.h index eebb9b9bd..429173df2 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2header.h +++ b/3rdparty/taglib/mpeg/id3v2/id3v2header.h @@ -151,7 +151,7 @@ class TAGLIB_EXPORT Header { void parse(const ByteVector &data); private: - explicit Header(const Header&); + Header(const Header&); Header &operator=(const Header&); class HeaderPrivate; diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp index 57700387b..f09f0cd0b 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp @@ -34,7 +34,7 @@ unsigned int SynchData::toUInt(const ByteVector &data) { unsigned int sum = 0; bool notSynchSafe = false; - int last = data.size() > 4 ? 3 : data.size() - 1; + const int last = data.size() > 4 ? 3 : data.size() - 1; for (int i = 0; i <= last; i++) { if (data[i] & 0x80) { @@ -49,12 +49,12 @@ unsigned int SynchData::toUInt(const ByteVector &data) { // Invalid data; assume this was created by some buggy software that just // put normal integers here rather than syncsafe ones, and try it that way. if (data.size() >= 4) { - sum = data.toUInt(0, true); + sum = data.toUInt32BE(0); } else { ByteVector tmp(data); tmp.resize(4); - sum = tmp.toUInt(0, true); + sum = tmp.toUInt32BE(0); } } diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp index f0a8e23ea..c330a539f 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp @@ -25,10 +25,11 @@ #include -#include -#include -#include -#include +#include "tfile.h" +#include "tbytevector.h" +#include "tpropertymap.h" +#include "tpicturemap.h" +#include "tdebug.h" #include "id3v2tag.h" #include "id3v2header.h" @@ -37,6 +38,7 @@ #include "id3v2synchdata.h" #include "id3v1genres.h" +#include "frames/attachedpictureframe.h" #include "frames/textidentificationframe.h" #include "frames/commentsframe.h" #include "frames/urllinkframe.h" @@ -48,20 +50,34 @@ using namespace Strawberry_TagLib::TagLib; using namespace ID3v2; namespace { -const ID3v2::Latin1StringHandler defaultStringHandler; -const ID3v2::Latin1StringHandler *stringHandler = &defaultStringHandler; +class DefaultStringHandler : public Strawberry_TagLib::TagLib::StringHandler { + public: + explicit DefaultStringHandler() : Strawberry_TagLib::TagLib::StringHandler() {} -const long MinPaddingSize = 1024; -const long MaxPaddingSize = 1024 * 1024; + String parse(const ByteVector &data) const override { + return String(data, String::Latin1); + } + + ByteVector render(const String&) const override { + // Not implemented on purpose. This function is never used. + return ByteVector(); + } +}; + +const DefaultStringHandler defaultStringHandler; +const Strawberry_TagLib::TagLib::StringHandler *stringHandler = &defaultStringHandler; + +const long long MinPaddingSize = 1024; +const long long MaxPaddingSize = 1024 * 1024; } // namespace class ID3v2::Tag::TagPrivate { public: - TagPrivate() : factory(nullptr), - file(nullptr), - tagOffset(0), - extendedHeader(nullptr), - footer(nullptr) { + explicit TagPrivate() : factory(nullptr), + file(nullptr), + tagOffset(0), + extendedHeader(nullptr), + footer(nullptr) { frameList.setAutoDelete(true); } @@ -73,7 +89,7 @@ class ID3v2::Tag::TagPrivate { const FrameFactory *factory; File *file; - long tagOffset; + long long tagOffset; Header header; ExtendedHeader *extendedHeader; @@ -83,18 +99,6 @@ class ID3v2::Tag::TagPrivate { FrameList frameList; }; -//////////////////////////////////////////////////////////////////////////////// -// StringHandler implementation -//////////////////////////////////////////////////////////////////////////////// - -Latin1StringHandler::Latin1StringHandler() {} - -Latin1StringHandler::~Latin1StringHandler() {} - -String Latin1StringHandler::parse(const ByteVector &data) const { - return String(data, String::Latin1); -} - //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -103,7 +107,7 @@ ID3v2::Tag::Tag() : d(new TagPrivate()) { d->factory = FrameFactory::instance(); } -ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) : d(new TagPrivate()) { +ID3v2::Tag::Tag(File *file, long long tagOffset, const FrameFactory *factory) : d(new TagPrivate()) { d->factory = factory; d->file = file; d->tagOffset = tagOffset; @@ -206,7 +210,90 @@ unsigned int ID3v2::Tag::track() const { if (!d->frameListMap["TRCK"].isEmpty()) return d->frameListMap["TRCK"].front()->toString().toInt(); + return 0; + +} + +Strawberry_TagLib::TagLib::PictureMap ID3v2::Tag::pictures() const { + + if (!d->frameListMap.contains("APIC")) + return PictureMap(); + + PictureMap map; + FrameList frameListMap = d->frameListMap["APIC"]; + for (FrameList::ConstIterator it = frameListMap.begin(); it != frameListMap.end(); ++it) { + const AttachedPictureFrame *frame = static_cast(*it); + Picture::Type type; + switch (frame->type()) { + case AttachedPictureFrame::FileIcon: + type = Picture::FileIcon; + break; + case AttachedPictureFrame::OtherFileIcon: + type = Picture::OtherFileIcon; + break; + case AttachedPictureFrame::FrontCover: + type = Picture::FrontCover; + break; + case AttachedPictureFrame::BackCover: + type = Picture::BackCover; + break; + case AttachedPictureFrame::LeafletPage: + type = Picture::LeafletPage; + break; + case AttachedPictureFrame::Media: + type = Picture::Media; + break; + case AttachedPictureFrame::LeadArtist: + type = Picture::LeadArtist; + break; + case AttachedPictureFrame::Artist: + type = Picture::Artist; + break; + case AttachedPictureFrame::Conductor: + type = Picture::Conductor; + break; + case AttachedPictureFrame::Band: + type = Picture::Band; + break; + case AttachedPictureFrame::Composer: + type = Picture::Composer; + break; + case AttachedPictureFrame::Lyricist: + type = Picture::Lyricist; + break; + case AttachedPictureFrame::RecordingLocation: + type = Picture::RecordingLocation; + break; + case AttachedPictureFrame::DuringRecording: + type = Picture::DuringRecording; + break; + case AttachedPictureFrame::DuringPerformance: + type = Picture::DuringPerformance; + break; + case AttachedPictureFrame::MovieScreenCapture: + type = Picture::MovieScreenCapture; + break; + case AttachedPictureFrame::ColouredFish: + type = Picture::ColouredFish; + break; + case AttachedPictureFrame::Illustration: + type = Picture::Illustration; + break; + case AttachedPictureFrame::BandLogo: + type = Picture::BandLogo; + break; + case AttachedPictureFrame::PublisherLogo: + type = Picture::PublisherLogo; + break; + default: + type = Picture::Other; + break; + } + Picture picture(frame->picture(), type, frame->mimeType(), frame->description()); + map.insert(picture); + } + return PictureMap(map); } @@ -282,6 +369,92 @@ void ID3v2::Tag::setTrack(unsigned int i) { setTextFrame("TRCK", String::number(i)); } +void ID3v2::Tag::setPictures(const PictureMap &l) { + + removeFrames("APIC"); + + for (PictureMap::ConstIterator it = l.begin(); it != l.end(); ++it) { + + PictureList list = it->second; + FrameList framesAdded; + for (PictureList::ConstIterator it2 = list.begin(); it2 != list.end(); ++it2) { + const Picture picture = (*it2); + AttachedPictureFrame *frame = new AttachedPictureFrame(); + frame->setPicture(picture.data()); + frame->setMimeType(picture.mime()); + frame->setDescription(picture.description()); + switch (picture.type()) { + case Picture::Other: + frame->setType(AttachedPictureFrame::Other); + break; + case Picture::FileIcon: + frame->setType(AttachedPictureFrame::FileIcon); + break; + case Picture::OtherFileIcon: + frame->setType(AttachedPictureFrame::OtherFileIcon); + break; + case Picture::FrontCover: + frame->setType(AttachedPictureFrame::FrontCover); + break; + case Picture::BackCover: + frame->setType(AttachedPictureFrame::BackCover); + break; + case Picture::LeafletPage: + frame->setType(AttachedPictureFrame::LeafletPage); + break; + case Picture::Media: + frame->setType(AttachedPictureFrame::Media); + break; + case Picture::LeadArtist: + frame->setType(AttachedPictureFrame::LeadArtist); + break; + case Picture::Artist: + frame->setType(AttachedPictureFrame::Artist); + break; + case Picture::Conductor: + frame->setType(AttachedPictureFrame::Conductor); + break; + case Picture::Band: + frame->setType(AttachedPictureFrame::Band); + break; + case Picture::Composer: + frame->setType(AttachedPictureFrame::Composer); + break; + case Picture::Lyricist: + frame->setType(AttachedPictureFrame::Lyricist); + break; + case Picture::RecordingLocation: + frame->setType(AttachedPictureFrame::RecordingLocation); + break; + case Picture::DuringRecording: + frame->setType(AttachedPictureFrame::DuringRecording); + break; + case Picture::DuringPerformance: + frame->setType(AttachedPictureFrame::DuringPerformance); + break; + case Picture::MovieScreenCapture: + frame->setType(AttachedPictureFrame::MovieScreenCapture); + break; + case Picture::ColouredFish: + frame->setType(AttachedPictureFrame::ColouredFish); + break; + case Picture::Illustration: + frame->setType(AttachedPictureFrame::Illustration); + break; + case Picture::BandLogo: + frame->setType(AttachedPictureFrame::BandLogo); + break; + case Picture::PublisherLogo: + frame->setType(AttachedPictureFrame::PublisherLogo); + break; + } + framesAdded.append(frame); + } + for (FrameList::ConstIterator it2 = framesAdded.begin(); it2 != framesAdded.end(); ++it2) + addFrame(*it2); + } +} + bool ID3v2::Tag::isEmpty() const { return d->frameList.isEmpty(); } @@ -430,10 +603,6 @@ PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps) { } -ByteVector ID3v2::Tag::render() const { - return render(ID3v2::v4); -} - 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", nullptr }; @@ -575,8 +744,8 @@ ByteVector ID3v2::Tag::render(Version version) const { // Compute the amount of padding, and append that to tagData. - long originalSize = d->header.tagSize(); - long paddingSize = originalSize - (tagData.size() - Header::size()); + long long originalSize = d->header.tagSize(); + long long paddingSize = originalSize - (tagData.size() - Header::size()); if (paddingSize <= 0) { paddingSize = MinPaddingSize; @@ -584,7 +753,7 @@ ByteVector ID3v2::Tag::render(Version version) const { else { // Padding won't increase beyond 1% of the file size or 1MB. - long threshold = d->file ? d->file->length() / 100 : 0; + long long threshold = d->file ? d->file->length() / 100 : 0; threshold = std::max(threshold, MinPaddingSize); threshold = std::min(threshold, MaxPaddingSize); @@ -606,11 +775,11 @@ ByteVector ID3v2::Tag::render(Version version) const { } -Latin1StringHandler const *ID3v2::Tag::latin1StringHandler() { +Strawberry_TagLib::TagLib::StringHandler const *ID3v2::Tag::latin1StringHandler() { return stringHandler; } -void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler) { +void ID3v2::Tag::setLatin1StringHandler(const Strawberry_TagLib::TagLib::StringHandler *handler) { if (handler) stringHandler = handler; else @@ -671,8 +840,8 @@ void ID3v2::Tag::parse(const ByteVector &origData) { if (d->header.unsynchronisation() && d->header.majorVersion() <= 3) data = SynchData::decode(data); - unsigned int frameDataPosition = 0; - unsigned int frameDataLength = data.size(); + size_t frameDataPosition = 0; + size_t frameDataLength = data.size(); // check for extended header diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2tag.h b/3rdparty/taglib/mpeg/id3v2/id3v2tag.h index 4b34b0a4d..ab9d8b826 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2tag.h +++ b/3rdparty/taglib/mpeg/id3v2/id3v2tag.h @@ -29,6 +29,7 @@ #include "tag.h" #include "tbytevector.h" #include "tstring.h" +#include "tstringhandler.h" #include "tlist.h" #include "tmap.h" #include "taglib_export.h" @@ -50,34 +51,6 @@ class Footer; typedef List FrameList; typedef Map FrameListMap; -//! An abstraction for the ISO-8859-1 string to data encoding in ID3v2 tags. - -/*! - * ID3v2 tag can store strings in ISO-8859-1 (Latin1), and TagLib only supports genuine ISO-8859-1 by default. - * However, in practice, non ISO-8859-1 encodings are often used instead of ISO-8859-1, - * such as Windows-1252 for western languages, Shift_JIS for Japanese and so on. - * - * Here is an option to read such tags by subclassing this class, - * reimplementing parse() and setting your reimplementation as the default - * with ID3v2::Tag::setStringHandler(). - * - * \note Writing non-ISO-8859-1 tags is not implemented intentionally. - * Use UTF-16 or UTF-8 instead. - * - * \see ID3v2::Tag::setStringHandler() - */ -class TAGLIB_EXPORT Latin1StringHandler { - public: - explicit Latin1StringHandler(); - virtual ~Latin1StringHandler(); - - /*! - * Decode a string from \a data. The default implementation assumes that - * \a data is an ISO-8859-1 (Latin1) character array. - */ - virtual String parse(const ByteVector &data) const; -}; - //! The main class in the ID3v2 implementation /*! @@ -133,32 +106,34 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * * \see FrameFactory */ - explicit Tag(File *file, long tagOffset, const FrameFactory *factory = FrameFactory::instance()); + explicit Tag(File *file, long long tagOffset, const FrameFactory *factory = FrameFactory::instance()); /*! * Destroys this Tag instance. */ - virtual ~Tag(); + ~Tag() override; // Reimplementations. - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; + PictureMap pictures() const override; - 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(unsigned int i); - virtual void setTrack(unsigned int i); + void setTitle(const String &s) override; + void setArtist(const String &s) override; + void setAlbum(const String &s) override; + void setComment(const String &s) override; + void setGenre(const String &s) override; + void setYear(unsigned int i) override; + void setTrack(unsigned int i) override; + void setPictures(const PictureMap &l) override; - virtual bool isEmpty() const; + bool isEmpty() const override; /*! * Returns a pointer to the tag's header. @@ -271,7 +246,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * once, the description, separated by a "/". * */ - PropertyMap properties() const; + PropertyMap properties() const override; /*! * Removes unsupported frames given by \a properties. The elements of @@ -284,32 +259,26 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * - "UNKNOWN/" + frameID, for frames that could not be parsed by TagLib. * In that case, *all* unknown frames with the given ID will be removed. */ - void removeUnsupportedProperties(const StringList &properties); + void removeUnsupportedProperties(const StringList &properties) override; /*! * Implements the unified property interface -- import function. * See the comments in properties(). */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Render the tag back to binary data, suitable to be written to disk. - */ - ByteVector render() const; + PropertyMap setProperties(const PropertyMap &) override; /*! * Render the tag back to binary data, suitable to be written to disk. * * The \a version parameter specifies whether ID3v2.4 (default) or ID3v2.3 should be used. */ - ByteVector render(Version version) const; + ByteVector render(Version version = ID3v2::v4) const; /*! * Gets the current string handler that decides how the "Latin-1" data will be converted to and from binary data. * - * \see Latin1StringHandler */ - static Latin1StringHandler const *latin1StringHandler(); + static Strawberry_TagLib::TagLib::StringHandler const *latin1StringHandler(); /*! * Sets the string handler that decides how the "Latin-1" data will be converted to and from binary data. @@ -319,7 +288,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * * \see Latin1StringHandler */ - static void setLatin1StringHandler(const Latin1StringHandler *handler); + static void setLatin1StringHandler(const Strawberry_TagLib::TagLib::StringHandler *handler); protected: /*! @@ -348,7 +317,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { void downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const; private: - explicit Tag(const Tag&); + Tag(const Tag&); Tag &operator=(const Tag&); class TagPrivate; diff --git a/3rdparty/taglib/mpeg/mpegfile.cpp b/3rdparty/taglib/mpeg/mpegfile.cpp index 95aa20899..ec08e2e5d 100644 --- a/3rdparty/taglib/mpeg/mpegfile.cpp +++ b/3rdparty/taglib/mpeg/mpegfile.cpp @@ -23,14 +23,14 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include +#include "tagunion.h" +#include "tagutils.h" +#include "id3v2tag.h" +#include "id3v2header.h" +#include "id3v1tag.h" +#include "apefooter.h" +#include "apetag.h" +#include "tdebug.h" #include "mpegfile.h" #include "mpegheader.h" @@ -63,15 +63,15 @@ class MPEG::File::FilePrivate { const ID3v2::FrameFactory *ID3v2FrameFactory; - long ID3v2Location; - long ID3v2OriginalSize; + long long ID3v2Location; + long long ID3v2OriginalSize; - long APELocation; - long APEOriginalSize; + long long APELocation; + long long APEOriginalSize; - long ID3v1Location; + long long ID3v1Location; - TagUnion tag; + TripleTagUnion tag; AudioProperties *properties; }; @@ -103,13 +103,13 @@ bool MPEG::File::isSupported(IOStream *stream) { // MPEG frame headers are really confusing with irrelevant binary data. // So we check if a frame header is really valid. - long headerOffset; + long long headerOffset; const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true, &headerOffset); if (buffer.isEmpty()) return false; - const long originalPosition = stream->tell(); + const long long originalPosition = stream->tell(); AdapterFile file(stream); for (unsigned int i = 0; i < buffer.size() - 1; ++i) { @@ -131,20 +131,25 @@ bool MPEG::File::isSupported(IOStream *stream) { // public members //////////////////////////////////////////////////////////////////////////////// -MPEG::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(frameFactory)) { +MPEG::File::File(FileName fileName, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(fileName), d(new FilePrivate()) { if (isOpen()) read(readProperties); } -MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate(frameFactory)) { +MPEG::File::File(FileName fileName, ID3v2::FrameFactory *frameFactory, bool readProperties, AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::File(fileName), d(new FilePrivate(frameFactory)) { if (isOpen()) read(readProperties); } +MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, AudioProperties::ReadStyle) : TagLib::File(stream), d(new FilePrivate(frameFactory)) { + if (isOpen()) + read(readProperties); +} + MPEG::File::~File() { delete d; } @@ -153,14 +158,6 @@ Strawberry_TagLib::TagLib::Tag *MPEG::File::tag() const { return &d->tag; } -PropertyMap MPEG::File::properties() const { - return d->tag.properties(); -} - -void MPEG::File::removeUnsupportedProperties(const StringList &properties) { - d->tag.removeUnsupportedProperties(properties); -} - PropertyMap MPEG::File::setProperties(const PropertyMap &properties) { // update ID3v1 tag if it exists, but ignore the return value @@ -180,10 +177,6 @@ bool MPEG::File::save() { return save(AllTags); } -bool MPEG::File::save(int tags) { - return save(tags, StripOthers); -} - bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, DuplicateTags duplicate) { if (readOnly()) { @@ -360,7 +353,7 @@ bool MPEG::File::strip(int tags, bool freeMemory) { } -long MPEG::File::nextFrameOffset(long position) { +long long MPEG::File::nextFrameOffset(long long position) { ByteVector frameSyncBytes(2, '\0'); @@ -370,7 +363,7 @@ long MPEG::File::nextFrameOffset(long position) { if (buffer.isEmpty()) return -1; - for (unsigned int i = 0; i < buffer.size(); ++i) { + for (size_t i = 0; i < buffer.size(); ++i) { frameSyncBytes[0] = frameSyncBytes[1]; frameSyncBytes[1] = buffer[i]; if (isFrameSync(frameSyncBytes)) { @@ -385,12 +378,12 @@ long MPEG::File::nextFrameOffset(long position) { } -long MPEG::File::previousFrameOffset(long position) { +long long MPEG::File::previousFrameOffset(long long position) { ByteVector frameSyncBytes(2, '\0'); while (position > 0) { - const long bufferLength = std::min(position, bufferSize()); + const long long bufferLength = std::min(position, bufferSize()); position -= bufferLength; seek(position); @@ -411,9 +404,9 @@ long MPEG::File::previousFrameOffset(long position) { } -long MPEG::File::firstFrameOffset() { +long long MPEG::File::firstFrameOffset() { - long position = 0; + long long position = 0; if (hasID3v2Tag()) position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize(); @@ -422,9 +415,9 @@ long MPEG::File::firstFrameOffset() { } -long MPEG::File::lastFrameOffset() { +long long MPEG::File::lastFrameOffset() { - long position; + long long position; if (hasAPETag()) position = d->APELocation - 1; @@ -491,7 +484,7 @@ void MPEG::File::read(bool readProperties) { } -long MPEG::File::findID3v2() { +long long MPEG::File::findID3v2() { if (!isValid()) return -1; @@ -512,7 +505,7 @@ long MPEG::File::findID3v2() { ByteVector frameSyncBytes(2, '\0'); ByteVector tagHeaderBytes(3, '\0'); - long position = 0; + long long position = 0; while (true) { seek(position); @@ -520,7 +513,7 @@ long MPEG::File::findID3v2() { if (buffer.isEmpty()) return -1; - for (unsigned int i = 0; i < buffer.size(); ++i) { + for (size_t i = 0; i < buffer.size(); ++i) { frameSyncBytes[0] = frameSyncBytes[1]; frameSyncBytes[1] = buffer[i]; if (isFrameSync(frameSyncBytes)) { diff --git a/3rdparty/taglib/mpeg/mpegfile.h b/3rdparty/taglib/mpeg/mpegfile.h index 9398018d8..ba846d7eb 100644 --- a/3rdparty/taglib/mpeg/mpegfile.h +++ b/3rdparty/taglib/mpeg/mpegfile.h @@ -78,6 +78,17 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { AllTags = 0xffff }; + /*! + * Constructs an MPEG file from \a file. If \a readProperties is true the + * file's audio properties will also be read. + * + * \note In the current implementation, \a propertiesStyle is ignored. + * + * \deprecated This constructor will be dropped in favor of the one below + * in a future version. + */ + explicit File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); + /*! * Constructs an MPEG file from \a file. * If \a readProperties is true the file's audio properties will also be read. @@ -88,7 +99,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \note In the current implementation, \a propertiesStyle is ignored. */ // BIC: merge with the above constructor - explicit File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); + explicit File(FileName fileName, ID3v2::FrameFactory *frameFactory, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Constructs an MPEG file from \a stream. @@ -105,7 +116,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns a pointer to a tag that is the union of the ID3v2 and ID3v1 tags. @@ -122,16 +133,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * \see ID3v2Tag() * \see APETag() */ - virtual Tag *tag() const; - - /*! - * Implements the reading part of the unified property interface. - * If the file contains more than one tag, - * only the first one (in the order ID3v2, APE, ID3v1) will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); + Tag *tag() const override; /*! * Implements the writing part of the unified tag dictionary interface. @@ -140,13 +142,13 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * If an ID3v1 tag exists, it will be updated as well, within the limitations of that format. * The returned PropertyMap refers to the ID3v2 tag only. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap&) override; /*! * Returns the MPEG::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this will duplicate its content into the other tag. @@ -161,18 +163,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * * \see save(int tags) */ - virtual bool save(); - - /*! - * Save the file. - * This will attempt to save all of the tag types that are specified by OR-ing together TagTypes values. - * The save() method above uses AllTags. This returns true if saving was successful. - * - * 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. - */ - bool save(int tags); + bool save() override; /*! * Save the file. This will attempt to save all of the tag types that are @@ -187,7 +178,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * If \a duplicate is set to DuplicateTags and at least one tag -- ID3v1 * or ID3v2 -- exists this will duplicate its content into the other tag. */ - bool save(int tags, StripTags strip, ID3v2::Version version = ID3v2::v4, DuplicateTags duplicate = Duplicate); + bool save(int tags, StripTags strip = StripOthers, ID3v2::Version version = ID3v2::v4, DuplicateTags duplicate = Duplicate); /*! * Returns a pointer to the ID3v2 tag of the file. @@ -266,22 +257,22 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Returns the position in the file of the first MPEG frame. */ - long firstFrameOffset(); + long long firstFrameOffset(); /*! * Returns the position in the file of the next MPEG frame, using the current position as start */ - long nextFrameOffset(long position); + long long nextFrameOffset(long long position); /*! * Returns the position in the file of the previous MPEG frame, using the current position as start */ - long previousFrameOffset(long position); + long long previousFrameOffset(long long position); /*! * Returns the position in the file of the last MPEG frame. */ - long lastFrameOffset(); + long long lastFrameOffset(); /*! * Returns whether or not the file on disk actually has an ID3v1 tag. @@ -312,11 +303,11 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); - long findID3v2(); + long long findID3v2(); class FilePrivate; FilePrivate *d; diff --git a/3rdparty/taglib/mpeg/mpegheader.cpp b/3rdparty/taglib/mpeg/mpegheader.cpp index 4bee43f50..58c7c3993 100644 --- a/3rdparty/taglib/mpeg/mpegheader.cpp +++ b/3rdparty/taglib/mpeg/mpegheader.cpp @@ -23,121 +23,118 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include +#include + +#include "tbytevector.h" +#include "tstring.h" +#include "tfile.h" +#include "tdebug.h" #include "mpegheader.h" #include "mpegutils.h" using namespace Strawberry_TagLib::TagLib; -class MPEG::Header::HeaderPrivate : public RefCounter { - public: - HeaderPrivate() : isValid(false), - version(Version1), - layer(0), - protectionEnabled(false), - bitrate(0), - sampleRate(0), - isPadded(false), - channelMode(Stereo), - isCopyrighted(false), - isOriginal(false), - frameLength(0), - samplesPerFrame(0) {} - +namespace { +struct HeaderData { bool isValid; - Version version; + MPEG::Header::Version version; int layer; bool protectionEnabled; int bitrate; int sampleRate; bool isPadded; - ChannelMode channelMode; + MPEG::Header::ChannelMode channelMode; bool isCopyrighted; bool isOriginal; int frameLength; int samplesPerFrame; }; +} // namespace + +class MPEG::Header::HeaderPrivate { + public: + explicit HeaderPrivate() : data(new HeaderData()) { + data->isValid = false; + data->layer = 0; + data->version = Version1; + data->protectionEnabled = false; + data->sampleRate = 0; + data->isPadded = false; + data->channelMode = Stereo; + data->isCopyrighted = false; + data->isOriginal = false; + data->frameLength = 0; + data->samplesPerFrame = 0; + } + std::shared_ptr data; +}; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -MPEG::Header::Header(File *file, long offset, bool checkLength) : d(new HeaderPrivate()) { +MPEG::Header::Header(File *file, long long offset, bool checkLength) : d(new HeaderPrivate()) { parse(file, offset, checkLength); } -MPEG::Header::Header(const Header &h) : d(h.d) { - d->ref(); -} +MPEG::Header::Header(const Header &h) : d(new HeaderPrivate(*h.d)) {} MPEG::Header::~Header() { - if (d->deref()) - delete d; + delete d; } bool MPEG::Header::isValid() const { - return d->isValid; + return d->data->isValid; } MPEG::Header::Version MPEG::Header::version() const { - return d->version; + return d->data->version; } int MPEG::Header::layer() const { - return d->layer; + return d->data->layer; } bool MPEG::Header::protectionEnabled() const { - return d->protectionEnabled; + return d->data->protectionEnabled; } int MPEG::Header::bitrate() const { - return d->bitrate; + return d->data->bitrate; } int MPEG::Header::sampleRate() const { - return d->sampleRate; + return d->data->sampleRate; } bool MPEG::Header::isPadded() const { - return d->isPadded; + return d->data->isPadded; } MPEG::Header::ChannelMode MPEG::Header::channelMode() const { - return d->channelMode; + return d->data->channelMode; } bool MPEG::Header::isCopyrighted() const { - return d->isCopyrighted; + return d->data->isCopyrighted; } bool MPEG::Header::isOriginal() const { - return d->isOriginal; + return d->data->isOriginal; } int MPEG::Header::frameLength() const { - return d->frameLength; + return d->data->frameLength; } int MPEG::Header::samplesPerFrame() const { - return d->samplesPerFrame; + return d->data->samplesPerFrame; } MPEG::Header &MPEG::Header::operator=(const Header &h) { - if (&h == this) - return *this; - - if (d->deref()) - delete d; - - d = h.d; - d->ref(); + *d = *h.d; return *this; } @@ -146,7 +143,7 @@ MPEG::Header &MPEG::Header::operator=(const Header &h) { // private members //////////////////////////////////////////////////////////////////////////////// -void MPEG::Header::parse(File *file, long offset, bool checkLength) { +void MPEG::Header::parse(File *file, long long offset, bool checkLength) { file->seek(offset); const ByteVector data = file->readBlock(4); @@ -168,11 +165,11 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { const int versionBits = (static_cast(data[1]) >> 3) & 0x03; if (versionBits == 0) - d->version = Version2_5; + d->data->version = Version2_5; else if (versionBits == 2) - d->version = Version2; + d->data->version = Version2; else if (versionBits == 3) - d->version = Version1; + d->data->version = Version1; else return; @@ -181,15 +178,15 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { const int layerBits = (static_cast(data[1]) >> 1) & 0x03; if (layerBits == 1) - d->layer = 3; + d->data->layer = 3; else if (layerBits == 2) - d->layer = 2; + d->data->layer = 2; else if (layerBits == 3) - d->layer = 1; + d->data->layer = 1; else return; - d->protectionEnabled = (static_cast(data[1] & 0x01) == 0); + d->data->protectionEnabled = (static_cast(data[1] & 0x01) == 0); // Set the bitrate @@ -208,17 +205,17 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { } }; - const int versionIndex = (d->version == Version1) ? 0 : 1; - const int layerIndex = (d->layer > 0) ? d->layer - 1 : 0; + const int versionIndex = (d->data->version == Version1) ? 0 : 1; + const int layerIndex = (d->data->layer > 0) ? d->data->layer - 1 : 0; // The bitrate index is encoded as the first 4 bits of the 3rd byte, // i.e. 1111xxxx const int bitrateIndex = (static_cast(data[2]) >> 4) & 0x0F; - d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex]; + d->data->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex]; - if (d->bitrate == 0) + if (d->data->bitrate == 0) return; // Set the sample rate @@ -233,22 +230,22 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { const int samplerateIndex = (static_cast(data[2]) >> 2) & 0x03; - d->sampleRate = sampleRates[d->version][samplerateIndex]; + d->data->sampleRate = sampleRates[d->data->version][samplerateIndex]; - if (d->sampleRate == 0) { + if (d->data->sampleRate == 0) { return; } // The channel mode is encoded as a 2 bit value at the end of the 3nd byte, // i.e. xxxxxx11 - d->channelMode = static_cast((static_cast(data[3]) >> 6) & 0x03); + d->data->channelMode = static_cast((static_cast(data[3]) >> 6) & 0x03); // TODO: Add mode extension for completeness - d->isOriginal = ((static_cast(data[3]) & 0x04) != 0); - d->isCopyrighted = ((static_cast(data[3]) & 0x08) != 0); - d->isPadded = ((static_cast(data[2]) & 0x02) != 0); + d->data->isOriginal = ((static_cast(data[3]) & 0x04) != 0); + d->data->isCopyrighted = ((static_cast(data[3]) & 0x08) != 0); + d->data->isPadded = ((static_cast(data[2]) & 0x02) != 0); // Samples per frame @@ -259,16 +256,16 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { { 1152, 576 } // Layer III }; - d->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex]; + d->data->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex]; // Calculate the frame length static const int paddingSize[3] = { 4, 1, 1 }; - d->frameLength = d->samplesPerFrame * d->bitrate * 125 / d->sampleRate; + d->data->frameLength = d->data->samplesPerFrame * d->data->bitrate * 125 / d->data->sampleRate; - if (d->isPadded) - d->frameLength += paddingSize[layerIndex]; + if (d->data->isPadded) + d->data->frameLength += paddingSize[layerIndex]; if (checkLength) { @@ -279,7 +276,7 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { // consistent. Otherwise, we assume that either or both of the frames are // broken. - file->seek(offset + d->frameLength); + file->seek(offset + d->data->frameLength); const ByteVector nextData = file->readBlock(4); if (nextData.size() < 4) @@ -287,8 +284,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { const unsigned int HeaderMask = 0xfffe0c00; - const unsigned int header = data.toUInt(0, true) & HeaderMask; - const unsigned int nextHeader = nextData.toUInt(0, true) & HeaderMask; + const unsigned int header = data.toUInt32BE(0) & HeaderMask; + const unsigned int nextHeader = nextData.toUInt32BE(0) & HeaderMask; if (header != nextHeader) return; @@ -296,6 +293,6 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) { // Now that we're done parsing, set this to be a valid frame. - d->isValid = true; + d->data->isValid = true; } diff --git a/3rdparty/taglib/mpeg/mpegheader.h b/3rdparty/taglib/mpeg/mpegheader.h index f5587db1a..8600344de 100644 --- a/3rdparty/taglib/mpeg/mpegheader.h +++ b/3rdparty/taglib/mpeg/mpegheader.h @@ -54,12 +54,12 @@ class TAGLIB_EXPORT Header { * check if the frame length is parsed and calculated correctly. * So it's suitable for seeking for the first valid frame. */ - explicit Header(File *file, long offset, bool checkLength = true); + explicit Header(File *file, long long offset, bool checkLength = true); /*! * Does a shallow copy of \a h. */ - explicit Header(const Header &h); + Header(const Header &h); /*! * Destroys this Header instance. @@ -159,7 +159,7 @@ class TAGLIB_EXPORT Header { Header &operator=(const Header &h); private: - void parse(File *file, long offset, bool checkLength); + void parse(File *file, long long offset, bool checkLength); class HeaderPrivate; HeaderPrivate *d; diff --git a/3rdparty/taglib/mpeg/mpegproperties.cpp b/3rdparty/taglib/mpeg/mpegproperties.cpp index 4eab8d1bf..31c914d8d 100644 --- a/3rdparty/taglib/mpeg/mpegproperties.cpp +++ b/3rdparty/taglib/mpeg/mpegproperties.cpp @@ -23,8 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include + +#include "tdebug.h" +#include "tstring.h" #include "audioproperties.h" #include "mpegproperties.h" @@ -37,23 +39,18 @@ using namespace Strawberry_TagLib::TagLib; class MPEG::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : xingHeader(nullptr), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - layer(0), - version(Header::Version1), - channelMode(Header::Stereo), - protectionEnabled(false), - isCopyrighted(false), - isOriginal(false) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + layer(0), + version(Header::Version1), + channelMode(Header::Stereo), + protectionEnabled(false), + isCopyrighted(false), + isOriginal(false) {} - ~AudioPropertiesPrivate() { - delete xingHeader; - } - - XingHeader *xingHeader; + std::unique_ptr xingHeader; int length; int bitrate; int sampleRate; @@ -70,7 +67,7 @@ class MPEG::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -MPEG::AudioProperties::AudioProperties(File *file, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +MPEG::AudioProperties::AudioProperties(File *file, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file); } @@ -99,7 +96,7 @@ int MPEG::AudioProperties::channels() const { } const MPEG::XingHeader *MPEG::AudioProperties::xingHeader() const { - return d->xingHeader; + return d->xingHeader.get(); } MPEG::Header::Version MPEG::AudioProperties::version() const { @@ -134,7 +131,7 @@ void MPEG::AudioProperties::read(File *file) { // Only the first valid frame is required if we have a VBR header. - const long firstFrameOffset = file->firstFrameOffset(); + const long long firstFrameOffset = file->firstFrameOffset(); if (firstFrameOffset < 0) { debug("MPEG::AudioProperties::read() -- Could not find an MPEG frame in the stream."); return; @@ -146,11 +143,9 @@ void MPEG::AudioProperties::read(File *file) { // VBR stream. file->seek(firstFrameOffset); - d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength())); - if (!d->xingHeader->isValid()) { - delete d->xingHeader; - d->xingHeader = nullptr; - } + d->xingHeader.reset(new XingHeader(file->readBlock(firstHeader.frameLength()))); + if (!d->xingHeader->isValid()) + d->xingHeader.reset(); if (d->xingHeader && firstHeader.samplesPerFrame() > 0 && firstHeader.sampleRate() > 0) { @@ -174,14 +169,14 @@ void MPEG::AudioProperties::read(File *file) { // Look for the last MPEG audio frame to calculate the stream length. - const long lastFrameOffset = file->lastFrameOffset(); + const long long lastFrameOffset = file->lastFrameOffset(); if (lastFrameOffset < 0) { debug("MPEG::AudioProperties::read() -- Could not find an MPEG frame in the stream."); return; } const Header lastHeader(file, lastFrameOffset, false); - const long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength(); + const long long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength(); if (streamLength > 0) d->length = static_cast(streamLength * 8.0 / d->bitrate + 0.5); } diff --git a/3rdparty/taglib/mpeg/mpegproperties.h b/3rdparty/taglib/mpeg/mpegproperties.h index a087316bf..7bb2e0bde 100644 --- a/3rdparty/taglib/mpeg/mpegproperties.h +++ b/3rdparty/taglib/mpeg/mpegproperties.h @@ -54,36 +54,36 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Destroys this MPEG AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns a pointer to the Xing/VBRI header if one exists or null if no Xing/VBRI header was found. @@ -121,9 +121,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro bool isOriginal() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - void read(File *file); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/mpeg/xingheader.cpp b/3rdparty/taglib/mpeg/xingheader.cpp index 3755d0586..c555a6701 100644 --- a/3rdparty/taglib/mpeg/xingheader.cpp +++ b/3rdparty/taglib/mpeg/xingheader.cpp @@ -23,9 +23,9 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tbytevector.h" +#include "tstring.h" +#include "tdebug.h" #include "xingheader.h" #include "mpegfile.h" @@ -34,7 +34,7 @@ using namespace Strawberry_TagLib::TagLib; class MPEG::XingHeader::XingHeaderPrivate { public: - XingHeaderPrivate() : frames(0), size(0), type(MPEG::XingHeader::Invalid) {} + explicit XingHeaderPrivate() : frames(0), size(0), type(MPEG::XingHeader::Invalid) {} unsigned int frames; unsigned int size; @@ -78,11 +78,11 @@ void MPEG::XingHeader::parse(const ByteVector &data) { // Look for a Xing header. - long offset = data.find("Xing"); - if (offset < 0) + size_t offset = data.find("Xing"); + if (offset == ByteVector::npos()) offset = data.find("Info"); - if (offset >= 0) { + if (offset != ByteVector::npos()) { // Xing header found. @@ -96,8 +96,8 @@ void MPEG::XingHeader::parse(const ByteVector &data) { return; } - d->frames = data.toUInt(offset + 8, true); - d->size = data.toUInt(offset + 12, true); + d->frames = data.toUInt32BE(offset + 8); + d->size = data.toUInt32BE(offset + 12); d->type = Xing; } else { @@ -106,7 +106,7 @@ void MPEG::XingHeader::parse(const ByteVector &data) { offset = data.find("VBRI"); - if (offset >= 0) { + if (offset != ByteVector::npos()) { // VBRI header found. @@ -115,8 +115,8 @@ void MPEG::XingHeader::parse(const ByteVector &data) { return; } - d->frames = data.toUInt(offset + 14, true); - d->size = data.toUInt(offset + 10, true); + d->frames = data.toUInt32BE(offset + 14); + d->size = data.toUInt32BE(offset + 10); d->type = VBRI; } } diff --git a/3rdparty/taglib/mpeg/xingheader.h b/3rdparty/taglib/mpeg/xingheader.h index 686ea7333..e17d6bd5c 100644 --- a/3rdparty/taglib/mpeg/xingheader.h +++ b/3rdparty/taglib/mpeg/xingheader.h @@ -103,7 +103,7 @@ class TAGLIB_EXPORT XingHeader { HeaderType type() const; private: - explicit XingHeader(const XingHeader&); + XingHeader(const XingHeader&); XingHeader &operator=(const XingHeader&); void parse(const ByteVector &data); diff --git a/3rdparty/taglib/ogg/flac/oggflacfile.cpp b/3rdparty/taglib/ogg/flac/oggflacfile.cpp index 78091a0a6..7d8113b92 100644 --- a/3rdparty/taglib/ogg/flac/oggflacfile.cpp +++ b/3rdparty/taglib/ogg/flac/oggflacfile.cpp @@ -23,11 +23,11 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include +#include "tbytevector.h" +#include "tstring.h" +#include "tdebug.h" +#include "tpropertymap.h" +#include "tagutils.h" #include #include "oggflacfile.h" @@ -37,13 +37,13 @@ using Strawberry_TagLib::TagLib::FLAC::AudioProperties; class Ogg::FLAC::File::FilePrivate { public: - FilePrivate() : comment(nullptr), - properties(nullptr), - streamStart(0), - streamLength(0), - scanned(false), - hasXiphComment(false), - commentPacket(0) {} + explicit FilePrivate() : comment(nullptr), + properties(nullptr), + streamStart(0), + streamLength(0), + scanned(false), + hasXiphComment(false), + commentPacket(0) {} ~FilePrivate() { delete comment; @@ -55,8 +55,8 @@ class Ogg::FLAC::File::FilePrivate { AudioProperties *properties; ByteVector streamInfoData; ByteVector xiphCommentData; - long streamStart; - long streamLength; + long long streamStart; + long long streamLength; bool scanned; bool hasXiphComment; @@ -71,7 +71,7 @@ bool Ogg::FLAC::File::isSupported(IOStream *stream) { // An Ogg FLAC file has IDs "OggS" and "fLaC" somewhere. const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); - return (buffer.find("OggS") >= 0 && buffer.find("fLaC") >= 0); + return (buffer.find("OggS") != ByteVector::npos() && buffer.find("fLaC") != ByteVector::npos()); } //////////////////////////////////////////////////////////////////////////////// @@ -100,14 +100,6 @@ Ogg::XiphComment *Ogg::FLAC::File::tag() const { return d->comment; } -PropertyMap Ogg::FLAC::File::properties() const { - return d->comment->properties(); -} - -PropertyMap Ogg::FLAC::File::setProperties(const PropertyMap &properties) { - return d->comment->setProperties(properties); -} - FLAC::AudioProperties *Ogg::FLAC::File::audioProperties() const { return d->properties; } @@ -121,7 +113,7 @@ bool Ogg::FLAC::File::save() { // Put the size in the first 32 bit (I assume no more than 24 bit are used) - ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size()); + ByteVector v = ByteVector::fromUInt32BE(d->xiphCommentData.size()); // Set the type of the metadata-block to be a Xiph / Vorbis comment @@ -192,7 +184,7 @@ ByteVector Ogg::FLAC::File::xiphCommentData() { return d->xiphCommentData; } -long Ogg::FLAC::File::streamLength() { +long long Ogg::FLAC::File::streamLength() { scan(); return d->streamLength; } @@ -208,7 +200,7 @@ void Ogg::FLAC::File::scan() { return; int ipacket = 0; - long overhead = 0; + long long overhead = 0; ByteVector metadataHeader = packet(ipacket); if (metadataHeader.isEmpty()) @@ -257,7 +249,7 @@ void Ogg::FLAC::File::scan() { char blockType = header[0] & 0x7f; bool lastBlock = (header[0] & 0x80) != 0; - unsigned int length = header.toUInt(1, 3, true); + unsigned int length = header.toUInt24BE(1); overhead += length; // Sanity: First block should be the stream_info metadata @@ -281,7 +273,7 @@ void Ogg::FLAC::File::scan() { blockType = header[0] & 0x7f; lastBlock = (header[0] & 0x80) != 0; - length = header.toUInt(1, 3, true); + length = header.toUInt24BE(1); overhead += length; if (blockType == 1) { diff --git a/3rdparty/taglib/ogg/flac/oggflacfile.h b/3rdparty/taglib/ogg/flac/oggflacfile.h index 21c4b6292..aa4348f6d 100644 --- a/3rdparty/taglib/ogg/flac/oggflacfile.h +++ b/3rdparty/taglib/ogg/flac/oggflacfile.h @@ -84,7 +84,7 @@ class TAGLIB_EXPORT File : public Ogg::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. This will always be a XiphComment. @@ -97,38 +97,24 @@ class TAGLIB_EXPORT File : public Ogg::File { * * \see hasXiphComment() */ - virtual XiphComment *tag() const; + XiphComment *tag() const override; /*! * Returns the FLAC::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; - - - /*! - * Implements the unified property interface -- export function. - * This forwards directly to XiphComment::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified tag dictionary interface -- import function. - * Like properties(), this is a forwarder to the file's XiphComment. - */ - PropertyMap setProperties(const PropertyMap &); - + AudioProperties *audioProperties() const override; /*! * Save the file. This will primarily save and update the XiphComment. * Returns true if the save is successful. */ - virtual bool save(); + bool save() override; /*! * Returns the length of the audio-stream, used by FLAC::AudioProperties for calculating the bitrate. */ - long streamLength(); + long long streamLength(); /*! * Returns whether or not the file on disk actually has a XiphComment. @@ -145,7 +131,7 @@ class TAGLIB_EXPORT File : public Ogg::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties, AudioProperties::ReadStyle propertiesStyle); diff --git a/3rdparty/taglib/ogg/oggfile.cpp b/3rdparty/taglib/ogg/oggfile.cpp index 1a9c58052..51db601f3 100644 --- a/3rdparty/taglib/ogg/oggfile.cpp +++ b/3rdparty/taglib/ogg/oggfile.cpp @@ -23,10 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include +#include "tbytevectorlist.h" +#include "tmap.h" +#include "tstring.h" +#include "tdebug.h" #include "oggfile.h" #include "oggpage.h" @@ -48,7 +48,7 @@ unsigned int nextPacketIndex(const Ogg::Page *page) { class Ogg::File::FilePrivate { public: - FilePrivate() : streamSerialNumber(0), firstPageHeader(nullptr), lastPageHeader(nullptr) { + explicit FilePrivate() : streamSerialNumber(0), firstPageHeader(nullptr), lastPageHeader(nullptr) { pages.setAutoDelete(true); } @@ -74,8 +74,7 @@ Ogg::File::~File() { ByteVector Ogg::File::packet(unsigned int i) { - // Check to see if we're called setPacket() for this packet since the last - // save: + // Check to see if we're called setPacket() for this packet since the last save: if (d->dirtyPackets.contains(i)) return d->dirtyPackets[i]; @@ -126,7 +125,7 @@ void Ogg::File::setPacket(unsigned int i, const ByteVector &p) { const Ogg::PageHeader *Ogg::File::firstPageHeader() { if (!d->firstPageHeader) { - const long firstPageHeaderOffset = find("OggS"); + const long long firstPageHeaderOffset = find("OggS"); if (firstPageHeaderOffset < 0) return nullptr; @@ -140,7 +139,7 @@ const Ogg::PageHeader *Ogg::File::firstPageHeader() { const Ogg::PageHeader *Ogg::File::lastPageHeader() { if (!d->lastPageHeader) { - const long lastPageHeaderOffset = rfind("OggS"); + const long long lastPageHeaderOffset = rfind("OggS"); if (lastPageHeaderOffset < 0) return nullptr; @@ -184,7 +183,7 @@ bool Ogg::File::readPages(unsigned int i) { while (true) { unsigned int packetIndex; - long offset; + long long offset; if (d->pages.isEmpty()) { packetIndex = 0; @@ -268,8 +267,8 @@ void Ogg::File::writePacket(unsigned int i, const ByteVector &packet) { for (it = pages.begin(); it != pages.end(); ++it) data.append((*it)->render()); - const unsigned long originalOffset = firstPage->fileOffset(); - const unsigned long originalLength = lastPage->fileOffset() + lastPage->size() - originalOffset; + const long long originalOffset = firstPage->fileOffset(); + const long long originalLength = lastPage->fileOffset() + lastPage->size() - originalOffset; insert(data, originalOffset, originalLength); @@ -278,7 +277,7 @@ void Ogg::File::writePacket(unsigned int i, const ByteVector &packet) { const int numberOfNewPages = pages.back()->pageSequenceNumber() - lastPage->pageSequenceNumber(); if (numberOfNewPages != 0) { - long pageOffset = originalOffset + data.size(); + long long pageOffset = originalOffset + data.size(); while (true) { Page page(this, pageOffset); diff --git a/3rdparty/taglib/ogg/oggfile.h b/3rdparty/taglib/ogg/oggfile.h index c3529b8fe..9b54db245 100644 --- a/3rdparty/taglib/ogg/oggfile.h +++ b/3rdparty/taglib/ogg/oggfile.h @@ -49,7 +49,7 @@ class PageHeader; class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { public: - virtual ~File(); + ~File() override; /*! * Returns the packet contents for the i-th packet (starting from zero) in the Ogg bitstream. @@ -73,7 +73,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { */ const PageHeader *lastPageHeader(); - virtual bool save(); + bool save() override; protected: /*! @@ -90,10 +90,10 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { * * \note TagLib will *not* take ownership of the stream, the caller is responsible for deleting it after the File object. */ - File(IOStream *stream); + explicit File(IOStream *stream); private: - explicit File(const File &); + File(const File &); File &operator=(const File &); /*! diff --git a/3rdparty/taglib/ogg/oggpage.cpp b/3rdparty/taglib/ogg/oggpage.cpp index 4a24a6060..85b33a916 100644 --- a/3rdparty/taglib/ogg/oggpage.cpp +++ b/3rdparty/taglib/ogg/oggpage.cpp @@ -25,8 +25,8 @@ #include -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "oggpage.h" #include "oggpageheader.h" @@ -86,16 +86,16 @@ ByteVector checksum(const ByteVector &v) { for (ByteVector::ConstIterator it = v.begin(); it != v.end(); ++it) sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ static_cast(*it)]; - return ByteVector::fromUInt(sum); + return ByteVector::fromUInt32LE(sum); } } // namespace class Ogg::Page::PagePrivate { public: - PagePrivate(File *f = nullptr, long pageOffset = -1) : file(f), fileOffset(pageOffset), header(f, pageOffset), firstPacketIndex(-1) {} + explicit PagePrivate(File *f = nullptr, long long pageOffset = -1) : file(f), fileOffset(pageOffset), header(f, pageOffset), firstPacketIndex(-1) {} File *file; - long fileOffset; + long long fileOffset; PageHeader header; int firstPacketIndex; ByteVectorList packets; @@ -105,13 +105,13 @@ class Ogg::Page::PagePrivate { // public members //////////////////////////////////////////////////////////////////////////////// -Ogg::Page::Page(Ogg::File *file, long pageOffset) : d(new PagePrivate(file, pageOffset)) {} +Ogg::Page::Page(Ogg::File *file, long long pageOffset) : d(new PagePrivate(file, pageOffset)) {} Ogg::Page::~Page() { delete d; } -long Ogg::Page::fileOffset() const { +long long Ogg::Page::fileOffset() const { return d->fileOffset; } diff --git a/3rdparty/taglib/ogg/oggpage.h b/3rdparty/taglib/ogg/oggpage.h index f45492e73..f9c18a5e6 100644 --- a/3rdparty/taglib/ogg/oggpage.h +++ b/3rdparty/taglib/ogg/oggpage.h @@ -54,14 +54,14 @@ class TAGLIB_EXPORT Page { /*! * Read an Ogg page from the \a file at the position \a pageOffset. */ - explicit Page(File *file, long pageOffset); + explicit Page(File *file, long long pageOffset); virtual ~Page(); /*! * Returns the page's position within the file (in bytes). */ - long fileOffset() const; + long long fileOffset() const; /*! * Returns a pointer to the header for this page. This pointer will become invalid when the page is deleted. @@ -193,7 +193,7 @@ class TAGLIB_EXPORT Page { bool containsLastPacket = false); private: - explicit Page(const Page &); + Page(const Page &); Page &operator=(const Page &); class PagePrivate; diff --git a/3rdparty/taglib/ogg/oggpageheader.cpp b/3rdparty/taglib/ogg/oggpageheader.cpp index 464993efb..68d791b6c 100644 --- a/3rdparty/taglib/ogg/oggpageheader.cpp +++ b/3rdparty/taglib/ogg/oggpageheader.cpp @@ -25,9 +25,9 @@ #include -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" +#include "taglib.h" #include "oggpageheader.h" #include "oggfile.h" @@ -36,16 +36,16 @@ using namespace Strawberry_TagLib::TagLib; class Ogg::PageHeader::PageHeaderPrivate { public: - PageHeaderPrivate() : isValid(false), - firstPacketContinued(false), - lastPacketCompleted(false), - firstPageOfStream(false), - lastPageOfStream(false), - absoluteGranularPosition(0), - streamSerialNumber(0), - pageSequenceNumber(-1), - size(0), - dataSize(0) {} + explicit PageHeaderPrivate() : isValid(false), + firstPacketContinued(false), + lastPacketCompleted(false), + firstPageOfStream(false), + lastPageOfStream(false), + absoluteGranularPosition(0), + streamSerialNumber(0), + pageSequenceNumber(-1), + size(0), + dataSize(0) {} bool isValid; List packetSizes; @@ -64,7 +64,7 @@ class Ogg::PageHeader::PageHeaderPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -Ogg::PageHeader::PageHeader(Ogg::File *file, long pageOffset) : d(new PageHeaderPrivate()) { +Ogg::PageHeader::PageHeader(Ogg::File *file, long long pageOffset) : d(new PageHeaderPrivate()) { if (file && pageOffset >= 0) read(file, pageOffset); @@ -174,15 +174,15 @@ ByteVector Ogg::PageHeader::render() const { // absolute granular position - data.append(ByteVector::fromLongLong(d->absoluteGranularPosition, false)); + data.append(ByteVector::fromUInt64LE(d->absoluteGranularPosition)); // stream serial number - data.append(ByteVector::fromUInt(d->streamSerialNumber, false)); + data.append(ByteVector::fromUInt32LE(d->streamSerialNumber)); // page sequence number - data.append(ByteVector::fromUInt(d->pageSequenceNumber, false)); + data.append(ByteVector::fromUInt32LE(d->pageSequenceNumber)); // checksum -- this is left empty and should be filled in by the Ogg::Page // class @@ -204,7 +204,7 @@ ByteVector Ogg::PageHeader::render() const { // private members //////////////////////////////////////////////////////////////////////////////// -void Ogg::PageHeader::read(Ogg::File *file, long pageOffset) { +void Ogg::PageHeader::read(Ogg::File *file, long long pageOffset) { file->seek(pageOffset); @@ -227,9 +227,9 @@ void Ogg::PageHeader::read(Ogg::File *file, long pageOffset) { d->firstPageOfStream = flags.test(1); d->lastPageOfStream = flags.test(2); - d->absoluteGranularPosition = data.toLongLong(6, false); - d->streamSerialNumber = data.toUInt(14, false); - d->pageSequenceNumber = data.toUInt(18, false); + d->absoluteGranularPosition = data.toInt64LE(6); + d->streamSerialNumber = data.toUInt32LE(14); + d->pageSequenceNumber = data.toUInt32LE(18); // Byte number 27 is the number of page segments, which is the only variable // length portion of the page header. After reading the number of page diff --git a/3rdparty/taglib/ogg/oggpageheader.h b/3rdparty/taglib/ogg/oggpageheader.h index 5d5cfedf0..dde50b258 100644 --- a/3rdparty/taglib/ogg/oggpageheader.h +++ b/3rdparty/taglib/ogg/oggpageheader.h @@ -48,7 +48,7 @@ class TAGLIB_EXPORT PageHeader { * Reads a PageHeader from \a file starting at \a pageOffset. * The defaults create a page with no (and as such, invalid) data that must be set later. */ - explicit PageHeader(File *file = 0, long pageOffset = -1); + explicit PageHeader(File *file = nullptr, long long pageOffset = -1); /*! * Deletes this instance of the PageHeader. @@ -200,10 +200,10 @@ class TAGLIB_EXPORT PageHeader { ByteVector render() const; private: - explicit PageHeader(const PageHeader&); + PageHeader(const PageHeader&); PageHeader &operator=(const PageHeader&); - void read(Ogg::File *file, long pageOffset); + void read(Ogg::File *file, long long pageOffset); ByteVector lacingValues() const; class PageHeaderPrivate; diff --git a/3rdparty/taglib/ogg/opus/opusfile.cpp b/3rdparty/taglib/ogg/opus/opusfile.cpp index 5acd7006c..fc8825d3d 100644 --- a/3rdparty/taglib/ogg/opus/opusfile.cpp +++ b/3rdparty/taglib/ogg/opus/opusfile.cpp @@ -27,10 +27,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "opusfile.h" @@ -39,7 +39,7 @@ using namespace Strawberry_TagLib::TagLib::Ogg; class Opus::File::FilePrivate { public: - FilePrivate() : comment(nullptr), properties(nullptr) {} + explicit FilePrivate() : comment(nullptr), properties(nullptr) {} ~FilePrivate() { delete comment; @@ -59,7 +59,7 @@ bool Ogg::Opus::File::isSupported(IOStream *stream) { // An Opus file has IDs "OggS" and "OpusHead" somewhere. const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); - return (buffer.find("OggS") >= 0 && buffer.find("OpusHead") >= 0); + return (buffer.find("OggS") != ByteVector::npos() && buffer.find("OpusHead") != ByteVector::npos()); } @@ -89,14 +89,6 @@ Ogg::XiphComment *Opus::File::tag() const { return d->comment; } -PropertyMap Opus::File::properties() const { - return d->comment->properties(); -} - -PropertyMap Opus::File::setProperties(const PropertyMap &properties) { - return d->comment->setProperties(properties); -} - Opus::AudioProperties *Opus::File::audioProperties() const { return d->properties; } diff --git a/3rdparty/taglib/ogg/opus/opusfile.h b/3rdparty/taglib/ogg/opus/opusfile.h index db077265d..ea42c0660 100644 --- a/3rdparty/taglib/ogg/opus/opusfile.h +++ b/3rdparty/taglib/ogg/opus/opusfile.h @@ -76,38 +76,26 @@ class TAGLIB_EXPORT File : public Ogg::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the XiphComment for this file. * XiphComment implements the tag interface, so this serves as the reimplementation of TagLib::File::tag(). */ - virtual Ogg::XiphComment *tag() const; - - /*! - * Implements the unified property interface -- export function. - * This forwards directly to XiphComment::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified tag dictionary interface -- import function. - * Like properties(), this is a forwarder to the file's XiphComment. - */ - PropertyMap setProperties(const PropertyMap &); + Ogg::XiphComment *tag() const override; /*! * Returns the Opus::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Returns whether or not the given \a stream can be opened as an Opus file. @@ -117,7 +105,7 @@ class TAGLIB_EXPORT File : public Ogg::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/ogg/opus/opusproperties.cpp b/3rdparty/taglib/ogg/opus/opusproperties.cpp index 6b5375e1f..0c293238e 100644 --- a/3rdparty/taglib/ogg/opus/opusproperties.cpp +++ b/3rdparty/taglib/ogg/opus/opusproperties.cpp @@ -27,8 +27,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" #include @@ -40,11 +40,11 @@ using namespace Strawberry_TagLib::TagLib::Ogg; class Opus::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - inputSampleRate(0), - channels(0), - opusVersion(0) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + inputSampleRate(0), + channels(0), + opusVersion(0) {} int length; int bitrate; @@ -57,7 +57,7 @@ class Opus::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -Opus::AudioProperties::AudioProperties(File *file, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +Opus::AudioProperties::AudioProperties(File *file, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file); } @@ -65,11 +65,11 @@ Opus::AudioProperties::~AudioProperties() { delete d; } -int Ogg::Opus::AudioProperties::lengthInSeconds() const { +int Opus::AudioProperties::lengthInSeconds() const { return d->length / 1000; } -int Ogg::Opus::AudioProperties::lengthInMilliseconds() const { +int Opus::AudioProperties::lengthInMilliseconds() const { return d->length; } @@ -111,7 +111,7 @@ void Opus::AudioProperties::read(File *file) { const ByteVector data = file->packet(0); // *Magic Signature* - unsigned int pos = 8; + size_t pos = 8; // *Version* (8 bits, unsigned) d->opusVersion = static_cast(data.at(pos)); @@ -122,11 +122,11 @@ void Opus::AudioProperties::read(File *file) { pos += 1; // *Pre-skip* (16 bits, unsigned, little endian) - const unsigned short preSkip = data.toUShort(pos, false); + const unsigned short preSkip = data.toUInt16LE(pos); pos += 2; // *Input Sample Rate* (32 bits, unsigned, little endian) - d->inputSampleRate = data.toUInt(pos, false); + d->inputSampleRate = data.toUInt32LE(pos); pos += 4; // *Output Gain* (16 bits, signed, little endian) @@ -147,14 +147,15 @@ void Opus::AudioProperties::read(File *file) { if (frameCount > 0) { const double length = frameCount * 1000.0 / 48000.0; - long fileLengthWithoutOverhead = file->length(); + //long fileLengthWithoutOverhead = file->length(); // Ignore the two mandatory header packets, see "3. Packet Organization" // in https://tools.ietf.org/html/rfc7845.html - for (unsigned int i = 0; i < 2; ++i) { - fileLengthWithoutOverhead -= file->packet(i).size(); - } + //for (unsigned int i = 0; i < 2; ++i) { + //fileLengthWithoutOverhead -= file->packet(i).size(); + //} d->length = static_cast(length + 0.5); - d->bitrate = static_cast(fileLengthWithoutOverhead * 8.0 / length + 0.5); + //d->bitrate = static_cast(fileLengthWithoutOverhead * 8.0 / length + 0.5); + d->bitrate = static_cast(file->length() * 8.0 / length + 0.5); } } else { diff --git a/3rdparty/taglib/ogg/opus/opusproperties.h b/3rdparty/taglib/ogg/opus/opusproperties.h index 20b201e37..9e73c899d 100644 --- a/3rdparty/taglib/ogg/opus/opusproperties.h +++ b/3rdparty/taglib/ogg/opus/opusproperties.h @@ -58,38 +58,38 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Destroys this Opus::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. * * \note Always returns 48000, because Opus can decode any stream at a sample rate of 8, 12, 16, 24, or 48 kHz, */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * The Opus codec supports decoding at multiple sample rates, there is no single sample rate of the encoded stream. @@ -103,9 +103,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int opusVersion() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - void read(File *file); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/ogg/speex/speexfile.cpp b/3rdparty/taglib/ogg/speex/speexfile.cpp index c02d8e626..c630667a8 100644 --- a/3rdparty/taglib/ogg/speex/speexfile.cpp +++ b/3rdparty/taglib/ogg/speex/speexfile.cpp @@ -27,10 +27,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "speexfile.h" @@ -39,7 +39,7 @@ using namespace Strawberry_TagLib::TagLib::Ogg; class Speex::File::FilePrivate { public: - FilePrivate() : comment(nullptr), properties(nullptr) {} + explicit FilePrivate() : comment(nullptr), properties(nullptr) {} ~FilePrivate() { delete comment; @@ -59,7 +59,7 @@ bool Ogg::Speex::File::isSupported(IOStream *stream) { // A Speex file has IDs "OggS" and "Speex " somewhere. const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); - return (buffer.find("OggS") >= 0 && buffer.find("Speex ") >= 0); + return (buffer.find("OggS") != ByteVector::npos() && buffer.find("Speex ") != ByteVector::npos()); } @@ -85,14 +85,6 @@ Ogg::XiphComment *Speex::File::tag() const { return d->comment; } -PropertyMap Speex::File::properties() const { - return d->comment->properties(); -} - -PropertyMap Speex::File::setProperties(const PropertyMap &properties) { - return d->comment->setProperties(properties); -} - Speex::AudioProperties *Speex::File::audioProperties() const { return d->properties; } diff --git a/3rdparty/taglib/ogg/speex/speexfile.h b/3rdparty/taglib/ogg/speex/speexfile.h index d3c633ec8..5e4993dc3 100644 --- a/3rdparty/taglib/ogg/speex/speexfile.h +++ b/3rdparty/taglib/ogg/speex/speexfile.h @@ -77,37 +77,25 @@ class TAGLIB_EXPORT File : public Ogg::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the XiphComment for this file. XiphComment implements the tag interface, so this serves as the reimplementation of TagLib::File::tag(). */ - virtual Ogg::XiphComment *tag() const; - - /*! - * Implements the unified property interface -- export function. - * This forwards directly to XiphComment::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified tag dictionary interface -- import function. - * Like properties(), this is a forwarder to the file's XiphComment. - */ - PropertyMap setProperties(const PropertyMap &); + Ogg::XiphComment *tag() const override; /*! * Returns the Speex::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Returns whether or not the given \a stream can be opened as a Speex file. @@ -117,7 +105,7 @@ class TAGLIB_EXPORT File : public Ogg::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/ogg/speex/speexproperties.cpp b/3rdparty/taglib/ogg/speex/speexproperties.cpp index 51f2e23a6..6e3219fe0 100644 --- a/3rdparty/taglib/ogg/speex/speexproperties.cpp +++ b/3rdparty/taglib/ogg/speex/speexproperties.cpp @@ -27,10 +27,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" -#include +#include "oggpageheader.h" #include "speexproperties.h" #include "speexfile.h" @@ -40,14 +40,14 @@ using namespace Strawberry_TagLib::TagLib::Ogg; class Speex::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - bitrateNominal(0), - sampleRate(0), - channels(0), - speexVersion(0), - vbr(false), - mode(0) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + bitrateNominal(0), + sampleRate(0), + channels(0), + speexVersion(0), + vbr(false), + mode(0) {} int length; int bitrate; @@ -63,7 +63,7 @@ class Speex::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -Speex::AudioProperties::AudioProperties(File *file, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +Speex::AudioProperties::AudioProperties(File *file, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file); } @@ -113,32 +113,32 @@ void Speex::AudioProperties::read(File *file) { return; } - unsigned int pos = 28; + size_t pos = 28; // speex_version_id; /**< Version for Speex (for checking compatibility) */ - d->speexVersion = data.toUInt(pos, false); + d->speexVersion = data.toUInt32LE(pos); pos += 4; // header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */ pos += 4; // rate; /**< Sampling rate used */ - d->sampleRate = data.toUInt(pos, false); + d->sampleRate = data.toUInt32LE(pos); pos += 4; // mode; /**< Mode used (0 for narrowband, 1 for wideband) */ - d->mode = data.toUInt(pos, false); + d->mode = data.toUInt32LE(pos); pos += 4; // mode_bitstream_version; /**< Version ID of the bit-stream */ pos += 4; // nb_channels; /**< Number of channels encoded */ - d->channels = data.toUInt(pos, false); + d->channels = data.toUInt32LE(pos); pos += 4; // bitrate; /**< Bit-rate used */ - d->bitrateNominal = data.toUInt(pos, false); + d->bitrateNominal = data.toUInt32LE(pos); pos += 4; // frame_size; /**< Size of frames */ @@ -146,7 +146,7 @@ void Speex::AudioProperties::read(File *file) { pos += 4; // vbr; /**< 1 for a VBR encoding, 0 otherwise */ - d->vbr = data.toUInt(pos, false) == 1; + d->vbr = data.toUInt32LE(pos) == 1; pos += 4; // frames_per_packet; /**< Number of frames stored per Ogg packet */ diff --git a/3rdparty/taglib/ogg/speex/speexproperties.h b/3rdparty/taglib/ogg/speex/speexproperties.h index 36996a541..b9adf93dc 100644 --- a/3rdparty/taglib/ogg/speex/speexproperties.h +++ b/3rdparty/taglib/ogg/speex/speexproperties.h @@ -52,26 +52,26 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Destroys this Speex::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the nominal bit rate as read from the Speex header in kb/s. @@ -81,12 +81,12 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the Speex version, currently "0" (as specified by the spec). @@ -94,9 +94,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int speexVersion() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - void read(File *file); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp b/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp index 1abdfc214..c8ff800f9 100644 --- a/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp +++ b/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp @@ -25,18 +25,18 @@ #include -#include -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "vorbisfile.h" using namespace Strawberry_TagLib::TagLib; -class Vorbis::File::FilePrivate { +class Ogg::Vorbis::File::FilePrivate { public: - FilePrivate() : comment(nullptr), properties(nullptr) {} + explicit FilePrivate() : comment(nullptr), properties(nullptr) {} ~FilePrivate() { delete comment; @@ -61,50 +61,43 @@ static const char vorbisCommentHeaderID[] = { 0x03, 'v', 'o', 'r', 'b', 'i', 's' // static members //////////////////////////////////////////////////////////////////////////////// -bool Vorbis::File::isSupported(IOStream *stream) { +bool Ogg::Vorbis::File::isSupported(IOStream *stream) { // An Ogg Vorbis file has IDs "OggS" and "\x01vorbis" somewhere. const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); - return (buffer.find("OggS") >= 0 && buffer.find("\x01vorbis") >= 0); + return (buffer.find("OggS") != ByteVector::npos() && buffer.find("\x01vorbis") != ByteVector::npos()); + } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -Vorbis::File::File(FileName file, bool readProperties, Strawberry_TagLib::TagLib::AudioProperties::ReadStyle) : Ogg::File(file), +Ogg::Vorbis::File::File(FileName file, bool readProperties, Strawberry_TagLib::TagLib::AudioProperties::ReadStyle) : Ogg::File(file), d(new FilePrivate()) { if (isOpen()) read(readProperties); } -Vorbis::File::File(IOStream *stream, bool readProperties, Strawberry_TagLib::TagLib::AudioProperties::ReadStyle) : Ogg::File(stream), +Ogg::Vorbis::File::File(IOStream *stream, bool readProperties, Strawberry_TagLib::TagLib::AudioProperties::ReadStyle) : Ogg::File(stream), d(new FilePrivate()) { if (isOpen()) read(readProperties); } -Vorbis::File::~File() { +Ogg::Vorbis::File::~File() { delete d; } -Ogg::XiphComment *Vorbis::File::tag() const { +Ogg::XiphComment *Ogg::Vorbis::File::tag() const { return d->comment; } -PropertyMap Vorbis::File::properties() const { - return d->comment->properties(); -} - -PropertyMap Vorbis::File::setProperties(const PropertyMap &properties) { - return d->comment->setProperties(properties); -} - -Vorbis::AudioProperties *Vorbis::File::audioProperties() const { +Ogg::Vorbis::AudioProperties *Ogg::Vorbis::File::audioProperties() const { return d->properties; } -bool Vorbis::File::save() { +bool Ogg::Vorbis::File::save() { ByteVector v(vorbisCommentHeaderID); @@ -122,12 +115,12 @@ bool Vorbis::File::save() { // private members //////////////////////////////////////////////////////////////////////////////// -void Vorbis::File::read(bool readProperties) { +void Ogg::Vorbis::File::read(bool readProperties) { ByteVector commentHeaderData = packet(1); if (commentHeaderData.mid(0, 7) != vorbisCommentHeaderID) { - debug("Vorbis::File::read() - Could not find the Vorbis comment header."); + debug("Ogg::Vorbis::File::read() - Could not find the Vorbis comment header."); setValid(false); return; } diff --git a/3rdparty/taglib/ogg/vorbis/vorbisfile.h b/3rdparty/taglib/ogg/vorbis/vorbisfile.h index 6961c093b..76d24d206 100644 --- a/3rdparty/taglib/ogg/vorbis/vorbisfile.h +++ b/3rdparty/taglib/ogg/vorbis/vorbisfile.h @@ -34,16 +34,7 @@ namespace Strawberry_TagLib { namespace TagLib { - -/* - * This is just to make this appear to be in the Ogg namespace in the documentation. - * The typedef below will make this work with the current code. - * In the next BIC version of TagLib this will be really moved into the Ogg namespace. - */ - -#ifdef DOXYGEN namespace Ogg { -#endif //! A namespace containing classes for Vorbis metadata @@ -79,38 +70,25 @@ class TAGLIB_EXPORT File : public Ogg::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the XiphComment for this file. * XiphComment implements the tag interface, so this serves as the reimplementation of TagLib::File::tag(). */ - virtual Ogg::XiphComment *tag() const; - - - /*! - * Implements the unified property interface -- export function. - * This forwards directly to XiphComment::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified tag dictionary interface -- import function. - * Like properties(), this is a forwarder to the file's XiphComment. - */ - PropertyMap setProperties(const PropertyMap &); + Ogg::XiphComment *tag() const override; /*! * Returns the Vorbis::AudioProperties for this file. If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Save the file. * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Check if the given \a stream can be opened as an Ogg Vorbis file. @@ -120,7 +98,7 @@ class TAGLIB_EXPORT File : public Ogg::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); @@ -128,23 +106,9 @@ class TAGLIB_EXPORT File : public Ogg::File { class FilePrivate; FilePrivate *d; }; + } // namespace Vorbis - -/* - * To keep compatibility with the current version put Vorbis in the Ogg namespace only in the docs and provide a typedef to make it work. - * In the next BIC version this will be removed and it will only exist in the Ogg namespace. - */ - -#ifdef DOXYGEN -} -#else -namespace Ogg { -namespace Vorbis { -typedef Strawberry_TagLib::TagLib::Vorbis::File File; -} } // namespace Ogg -#endif - } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp b/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp index 8d68557b3..f96c2d7b4 100644 --- a/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp +++ b/3rdparty/taglib/ogg/vorbis/vorbisproperties.cpp @@ -23,26 +23,26 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" -#include +#include "oggpageheader.h" #include "vorbisproperties.h" #include "vorbisfile.h" using namespace Strawberry_TagLib::TagLib; -class Vorbis::AudioProperties::AudioPropertiesPrivate { +class Ogg::Vorbis::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - channels(0), - vorbisVersion(0), - bitrateMaximum(0), - bitrateNominal(0), - bitrateMinimum(0) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + vorbisVersion(0), + bitrateMaximum(0), + bitrateNominal(0), + bitrateMinimum(0) {} int length; int bitrate; @@ -60,7 +60,7 @@ namespace TagLib { * Vorbis headers can be found with one type ID byte and the string "vorbis" in * an Ogg stream. 0x01 indicates the setup header. */ -static const char vorbisSetupHeaderID[] = { 0x01, 'v', 'o', 'r', 'b', 'i', 's', 0 }; +const char vorbisSetupHeaderID[] = { 0x01, 'v', 'o', 'r', 'b', 'i', 's', 0 }; } // namespace TagLib } // namespace Strawberry_TagLib @@ -68,89 +68,99 @@ static const char vorbisSetupHeaderID[] = { 0x01, 'v', 'o', 'r', 'b', 'i', 's', // public members //////////////////////////////////////////////////////////////////////////////// -Vorbis::AudioProperties::AudioProperties(File *file, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +Ogg::Vorbis::AudioProperties::AudioProperties(File *file, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file); } -Vorbis::AudioProperties::~AudioProperties() { +Ogg::Vorbis::AudioProperties::~AudioProperties() { delete d; } -int Vorbis::AudioProperties::lengthInSeconds() const { +int Ogg::Vorbis::AudioProperties::lengthInSeconds() const { return d->length / 1000; } -int Vorbis::AudioProperties::lengthInMilliseconds() const { +int Ogg::Vorbis::AudioProperties::lengthInMilliseconds() const { return d->length; } -int Vorbis::AudioProperties::bitrate() const { +int Ogg::Vorbis::AudioProperties::bitrate() const { return d->bitrate; } -int Vorbis::AudioProperties::sampleRate() const { +int Ogg::Vorbis::AudioProperties::sampleRate() const { return d->sampleRate; } -int Vorbis::AudioProperties::channels() const { +int Ogg::Vorbis::AudioProperties::channels() const { return d->channels; } -int Vorbis::AudioProperties::vorbisVersion() const { +int Ogg::Vorbis::AudioProperties::vorbisVersion() const { return d->vorbisVersion; } -int Vorbis::AudioProperties::bitrateMaximum() const { +int Ogg::Vorbis::AudioProperties::bitrateMaximum() const { return d->bitrateMaximum; } -int Vorbis::AudioProperties::bitrateNominal() const { +int Ogg::Vorbis::AudioProperties::bitrateNominal() const { return d->bitrateNominal; } -int Vorbis::AudioProperties::bitrateMinimum() const { +int Ogg::Vorbis::AudioProperties::bitrateMinimum() const { return d->bitrateMinimum; } +String Ogg::Vorbis::AudioProperties::toString() const { + + StringList desc; + desc.append("Ogg Vorbis audio (version " + String::number(vorbisVersion()) + ")"); + desc.append(String::number(lengthInSeconds()) + " seconds"); + desc.append(String::number(bitrate()) + " kbps"); + return desc.toString(", "); + +} + //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// -void Vorbis::AudioProperties::read(File *file) { +void Ogg::Vorbis::AudioProperties::read(File *file) { // Get the identification header from the Ogg implementation. const ByteVector data = file->packet(0); if (data.size() < 28) { - debug("Vorbis::AudioProperties::read() -- data is too short."); + debug("Ogg::Vorbis::AudioProperties::read() -- data is too short."); return; } - unsigned int pos = 0; + size_t pos = 0; if (data.mid(pos, 7) != vorbisSetupHeaderID) { - debug("Vorbis::AudioProperties::read() -- invalid Vorbis identification header"); + debug("Ogg::Vorbis::AudioProperties::read() -- invalid Vorbis identification header"); return; } pos += 7; - d->vorbisVersion = data.toUInt(pos, false); + d->vorbisVersion = data.toUInt32LE(pos); pos += 4; d->channels = static_cast(data[pos]); pos += 1; - d->sampleRate = data.toUInt(pos, false); + d->sampleRate = data.toUInt32LE(pos); pos += 4; - d->bitrateMaximum = data.toUInt(pos, false); + d->bitrateMaximum = data.toUInt32LE(pos); pos += 4; - d->bitrateNominal = data.toUInt(pos, false); + d->bitrateNominal = data.toUInt32LE(pos); pos += 4; - d->bitrateMinimum = data.toUInt(pos, false); + d->bitrateMinimum = data.toUInt32LE(pos); pos += 4; // Find the length of the file. See http://wiki.xiph.org/VorbisStreamLength/ @@ -168,23 +178,24 @@ void Vorbis::AudioProperties::read(File *file) { if (frameCount > 0) { const double length = frameCount * 1000.0 / d->sampleRate; - long fileLengthWithoutOverhead = file->length(); + //long fileLengthWithoutOverhead = file->length(); // Ignore the three initial header packets, see "1.3.1. Decode Setup" in // https://xiph.org/vorbis/doc/Vorbis_I_spec.html - for (unsigned int i = 0; i < 3; ++i) { - fileLengthWithoutOverhead -= file->packet(i).size(); - } + //for (unsigned int i = 0; i < 3; ++i) { + //fileLengthWithoutOverhead -= file->packet(i).size(); + //} d->length = static_cast(length + 0.5); - d->bitrate = static_cast(fileLengthWithoutOverhead * 8.0 / length + 0.5); + //d->bitrate = static_cast(fileLengthWithoutOverhead * 8.0 / length + 0.5); + d->bitrate = static_cast(file->length() * 8.0 / length + 0.5); } } else { - debug("Vorbis::AudioProperties::read() -- Either the PCM values for the start or " + debug("Ogg::Vorbis::AudioProperties::read() -- Either the PCM values for the start or " "end of this file was incorrect or the sample rate is zero."); } } else - debug("Vorbis::AudioProperties::read() -- Could not find valid first and last Ogg pages."); + debug("Ogg::Vorbis::AudioProperties::read() -- Could not find valid first and last Ogg pages."); // Alternative to the actual average bitrate. diff --git a/3rdparty/taglib/ogg/vorbis/vorbisproperties.h b/3rdparty/taglib/ogg/vorbis/vorbisproperties.h index 1dcc05fe0..20539b2dd 100644 --- a/3rdparty/taglib/ogg/vorbis/vorbisproperties.h +++ b/3rdparty/taglib/ogg/vorbis/vorbisproperties.h @@ -31,16 +31,7 @@ namespace Strawberry_TagLib { namespace TagLib { - -/* - * This is just to make this appear to be in the Ogg namespace in the documentation. - * The typedef below will make this work with the current code. - * In the next BIC version of TagLib this will be really moved into the Ogg namespace. - */ - -#ifdef DOXYGEN namespace Ogg { -#endif namespace Vorbis { @@ -62,36 +53,38 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Destroys this VorbisProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; + + String toString() const override; /*! * Returns the Vorbis version, currently "0" (as specified by the spec). @@ -114,31 +107,14 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int bitrateMinimum() const; private: - explicit AudioProperties(const AudioProperties &); - AudioProperties &operator=(const AudioProperties &); - void read(File *file); class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; + } // namespace Vorbis - -/* - * To keep compatibility with the current version put Vorbis in the Ogg namespace only in the docs and provide a typedef to make it work. - * In the next BIC version this will be removed and it will only exist in the Ogg namespace. - */ - -#ifdef DOXYGEN -} -#else -namespace Ogg { -namespace Vorbis { -typedef Strawberry_TagLib::TagLib::AudioProperties AudioProperties; -} } // namespace Ogg -#endif - } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/ogg/xiphcomment.cpp b/3rdparty/taglib/ogg/xiphcomment.cpp index 18a085640..859ec62eb 100644 --- a/3rdparty/taglib/ogg/xiphcomment.cpp +++ b/3rdparty/taglib/ogg/xiphcomment.cpp @@ -26,9 +26,10 @@ #include #include -#include -#include -#include +#include "flacpicture.h" +#include "xiphcomment.h" +#include "tpicturemap.h" +#include "tpropertymap.h" using namespace Strawberry_TagLib::TagLib; @@ -36,21 +37,21 @@ namespace { typedef Ogg::FieldListMap::Iterator FieldIterator; typedef Ogg::FieldListMap::ConstIterator FieldConstIterator; -typedef List PictureList; -typedef PictureList::Iterator PictureIterator; -typedef PictureList::Iterator PictureConstIterator; +typedef List XiphPictureList; +typedef XiphPictureList::Iterator PictureIterator; +typedef XiphPictureList::Iterator PictureConstIterator; } // namespace class Ogg::XiphComment::XiphCommentPrivate { public: - XiphCommentPrivate() { + explicit XiphCommentPrivate() { pictureList.setAutoDelete(true); } FieldListMap fieldListMap; String vendorID; String commentField; - PictureList pictureList; + XiphPictureList pictureList; }; //////////////////////////////////////////////////////////////////////////////// @@ -131,10 +132,15 @@ unsigned int Ogg::XiphComment::track() const { return d->fieldListMap["TRACKNUMBER"].front().toInt(); if (!d->fieldListMap["TRACKNUM"].isEmpty()) return d->fieldListMap["TRACKNUM"].front().toInt(); + return 0; } +Strawberry_TagLib::TagLib::PictureMap Ogg::XiphComment::pictures() const { + return PictureMap(); +} + void Ogg::XiphComment::setTitle(const String &s) { addField("TITLE", s); } @@ -184,6 +190,8 @@ void Ogg::XiphComment::setTrack(unsigned int i) { } +void Ogg::XiphComment::setPictures(const PictureMap&) {} + bool Ogg::XiphComment::isEmpty() const { for (FieldConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) { @@ -197,7 +205,7 @@ bool Ogg::XiphComment::isEmpty() const { unsigned int Ogg::XiphComment::fieldCount() const { - unsigned int count = 0; + size_t count = 0; for (FieldConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) count += (*it).second.size(); @@ -347,12 +355,12 @@ ByteVector Ogg::XiphComment::render(bool addFramingBit) const { ByteVector vendorData = d->vendorID.data(String::UTF8); - data.append(ByteVector::fromUInt(vendorData.size(), false)); + data.append(ByteVector::fromUInt32LE(vendorData.size())); data.append(vendorData); // Add the number of fields. - data.append(ByteVector::fromUInt(fieldCount(), false)); + data.append(ByteVector::fromUInt32LE(fieldCount())); // Iterate over the the field lists. Our iterator returns a // std::pair where the first String is the field name and @@ -371,14 +379,14 @@ ByteVector Ogg::XiphComment::render(bool addFramingBit) const { fieldData.append('='); fieldData.append((*valuesIt).data(String::UTF8)); - data.append(ByteVector::fromUInt(fieldData.size(), false)); + data.append(ByteVector::fromUInt32LE(fieldData.size())); data.append(fieldData); } } 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(ByteVector::fromUInt32LE(picture.size() + 23)); data.append("METADATA_BLOCK_PICTURE="); data.append(picture); } @@ -392,6 +400,18 @@ ByteVector Ogg::XiphComment::render(bool addFramingBit) const { } +String Ogg::XiphComment::toString() const { + + StringList desc; + for (FieldListMap::ConstIterator i = d->fieldListMap.begin(); i != d->fieldListMap.end(); i++) { + for (StringList::ConstIterator j = i->second.begin(); j != i->second.end(); j++) { + desc.append(i->first + "=" + *j); + } + } + return desc.toString("\n"); + +} + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// @@ -401,9 +421,9 @@ void Ogg::XiphComment::parse(const ByteVector &data) { // The first thing in the comment data is the vendor ID length, followed by a // UTF8 string with the vendor ID. - unsigned int pos = 0; + size_t pos = 0; - const unsigned int vendorLength = data.toUInt(0, false); + const unsigned int vendorLength = data.toUInt32LE(0); pos += 4; d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); @@ -411,7 +431,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) { // Next the number of fields in the comment vector. - const unsigned int commentFields = data.toUInt(pos, false); + const unsigned int commentFields = data.toUInt32LE(pos); pos += 4; if (commentFields > (data.size() - 8) / 4) { @@ -423,7 +443,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) { // 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 unsigned int commentLength = data.toUInt(pos, false); + const unsigned int commentLength = data.toUInt32LE(pos); pos += 4; const ByteVector entry = data.mid(pos, commentLength); @@ -436,8 +456,8 @@ void Ogg::XiphComment::parse(const ByteVector &data) { // Check for field separator - const int sep = entry.find('='); - if (sep < 1) { + const size_t sep = entry.find('='); + if (sep == 0 || sep == ByteVector::npos()) { debug("Ogg::XiphComment::parse() - Discarding a field. Separator not found."); continue; } diff --git a/3rdparty/taglib/ogg/xiphcomment.h b/3rdparty/taglib/ogg/xiphcomment.h index 2140fb2f8..3041aedf3 100644 --- a/3rdparty/taglib/ogg/xiphcomment.h +++ b/3rdparty/taglib/ogg/xiphcomment.h @@ -37,7 +37,6 @@ namespace Strawberry_TagLib { namespace TagLib { - namespace Ogg { /*! @@ -76,25 +75,28 @@ class TAGLIB_EXPORT XiphComment : public Strawberry_TagLib::TagLib::Tag { /*! * Destroys this instance of the XiphComment. */ - virtual ~XiphComment(); + ~XiphComment() override; - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; + PictureMap pictures() const override; - 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(unsigned int i); - virtual void setTrack(unsigned int i); + void setTitle(const String &s) override; + void setArtist(const String &s) override; + void setAlbum(const String &s) override; + void setComment(const String &s) override; + void setGenre(const String &s) override; + void setYear(unsigned int i) override; + void setTrack(unsigned int i) override; + void setPictures(const PictureMap&) override; - virtual bool isEmpty() const; + bool isEmpty() const override; + String toString() const override; /*! * Returns the number of fields present in the comment. @@ -142,7 +144,7 @@ class TAGLIB_EXPORT XiphComment : public Strawberry_TagLib::TagLib::Tag { * since it is completely compatible with the property interface * (in fact, a Xiph comment is nothing more than a map from tag names to list of values, as is the dict interface). */ - PropertyMap properties() const; + PropertyMap properties() const override; /*! * Implements the unified property interface -- import function. @@ -150,7 +152,7 @@ class TAGLIB_EXPORT XiphComment : public Strawberry_TagLib::TagLib::Tag { * except for invalid keys (less than one character, non-ASCII, * or containing '=' or '~') in which case the according values will be contained in the returned PropertyMap. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap&) override; /*! * Check if the given String is a valid Xiph comment key. @@ -238,7 +240,7 @@ class TAGLIB_EXPORT XiphComment : public Strawberry_TagLib::TagLib::Tag { void parse(const ByteVector &data); private: - explicit XiphComment(const XiphComment&); + XiphComment(const XiphComment&); XiphComment &operator=(const XiphComment&); class XiphCommentPrivate; diff --git a/3rdparty/taglib/riff/aiff/aifffile.cpp b/3rdparty/taglib/riff/aiff/aifffile.cpp index d68a9396f..8b495f61f 100644 --- a/3rdparty/taglib/riff/aiff/aifffile.cpp +++ b/3rdparty/taglib/riff/aiff/aifffile.cpp @@ -23,12 +23,14 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include +#include + +#include "tbytevector.h" +#include "tdebug.h" +#include "id3v2tag.h" +#include "tstringlist.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "aifffile.h" @@ -36,15 +38,10 @@ using namespace Strawberry_TagLib::TagLib; class RIFF::AIFF::File::FilePrivate { public: - FilePrivate() : properties(nullptr), tag(nullptr), hasID3v2(false) {} + FilePrivate() : hasID3v2(false) {} - ~FilePrivate() { - delete properties; - delete tag; - } - - AudioProperties *properties; - ID3v2::Tag *tag; + std::unique_ptr properties; + std::unique_ptr tag; bool hasID3v2; }; @@ -83,23 +80,11 @@ RIFF::AIFF::File::~File() { } ID3v2::Tag *RIFF::AIFF::File::tag() const { - return d->tag; -} - -PropertyMap RIFF::AIFF::File::properties() const { - return d->tag->properties(); -} - -void RIFF::AIFF::File::removeUnsupportedProperties(const StringList &properties) { - d->tag->removeUnsupportedProperties(properties); -} - -PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties) { - return d->tag->setProperties(properties); + return d->tag.get(); } RIFF::AIFF::AudioProperties *RIFF::AIFF::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool RIFF::AIFF::File::save() { @@ -147,7 +132,7 @@ void RIFF::AIFF::File::read(bool readProperties) { const ByteVector name = chunkName(i); if (name == "ID3 " || name == "id3 ") { if (!d->tag) { - d->tag = new ID3v2::Tag(this, chunkOffset(i)); + d->tag.reset(new ID3v2::Tag(this, chunkOffset(i))); d->hasID3v2 = true; } else { @@ -157,9 +142,9 @@ void RIFF::AIFF::File::read(bool readProperties) { } if (!d->tag) - d->tag = new ID3v2::Tag(); + d->tag.reset(new ID3v2::Tag()); if (readProperties) - d->properties = new AudioProperties(this, AudioProperties::Average); + d->properties.reset(new AudioProperties(this, AudioProperties::Average)); } diff --git a/3rdparty/taglib/riff/aiff/aifffile.h b/3rdparty/taglib/riff/aiff/aifffile.h index 91c003801..c527b37a0 100644 --- a/3rdparty/taglib/riff/aiff/aifffile.h +++ b/3rdparty/taglib/riff/aiff/aifffile.h @@ -78,7 +78,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::RIFF::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. @@ -88,32 +88,18 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::RIFF::File { * * \see hasID3v2Tag() */ - virtual ID3v2::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * This method forwards to ID3v2::Tag::properties(). - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * This method forwards to ID3v2::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); + ID3v2::Tag *tag() const override; /*! * Returns the AIFF::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Saves the file. */ - virtual bool save(); + bool save() override; /*! * Save using a specific ID3v2 version (e.g. v3) @@ -136,7 +122,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::RIFF::File { static bool isSupported(IOStream *stream); private: - explicit File(const File &); + File(const File &); File &operator=(const File &); void read(bool readProperties); diff --git a/3rdparty/taglib/riff/aiff/aiffproperties.cpp b/3rdparty/taglib/riff/aiff/aiffproperties.cpp index b40107206..40dbafc4a 100644 --- a/3rdparty/taglib/riff/aiff/aiffproperties.cpp +++ b/3rdparty/taglib/riff/aiff/aiffproperties.cpp @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "aifffile.h" #include "aiffproperties.h" @@ -55,7 +55,7 @@ class RIFF::AIFF::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -RIFF::AIFF::AudioProperties::AudioProperties(File *file, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +RIFF::AIFF::AudioProperties::AudioProperties(File *file, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file); } @@ -137,9 +137,9 @@ void RIFF::AIFF::AudioProperties::read(File *file) { return; } - d->channels = data.toShort(0U); - d->sampleFrames = data.toUInt(2U); - d->bitsPerSample = data.toShort(6U); + d->channels = data.toUInt16BE(0); + d->sampleFrames = data.toUInt32BE(2); + d->bitsPerSample = data.toUInt16BE(6); const long double sampleRate = data.toFloat80BE(8); if (sampleRate >= 1.0) diff --git a/3rdparty/taglib/riff/aiff/aiffproperties.h b/3rdparty/taglib/riff/aiff/aiffproperties.h index 82aedfa95..f53a99960 100644 --- a/3rdparty/taglib/riff/aiff/aiffproperties.h +++ b/3rdparty/taglib/riff/aiff/aiffproperties.h @@ -52,36 +52,36 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Destroys this AIFF::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -117,9 +117,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro String compressionName() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - void read(File *file); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/riff/rifffile.cpp b/3rdparty/taglib/riff/rifffile.cpp index 80bc3f6f5..2e99e9318 100644 --- a/3rdparty/taglib/riff/rifffile.cpp +++ b/3rdparty/taglib/riff/rifffile.cpp @@ -26,30 +26,46 @@ #include #include -#include -#include -#include +#include "tbytevector.h" +#include "tdebug.h" +#include "tstring.h" #include "rifffile.h" #include "riffutils.h" using namespace Strawberry_TagLib::TagLib; +namespace { struct Chunk { ByteVector name; - unsigned int offset; + long long offset; unsigned int size; unsigned int padding; }; +unsigned int toUInt32(const ByteVector &v, size_t offset, ByteOrder endian) { + if (endian == BigEndian) + return v.toUInt32BE(offset); + else + return v.toUInt32LE(offset); +} + +ByteVector fromUInt32(size_t value, ByteOrder endian) { + if (endian == BigEndian) + return ByteVector::fromUInt32BE(value); + else + return ByteVector::fromUInt32LE(value); +} +} // namespace + class RIFF::File::FilePrivate { public: - explicit FilePrivate(Endianness _endianness) : endianness(_endianness), size(0), sizeOffset(0) {} + explicit FilePrivate(ByteOrder _endianness) : endianness(_endianness), size(0), sizeOffset(0) {} - const Endianness endianness; + const ByteOrder endianness; unsigned int size; - long sizeOffset; + long long sizeOffset; std::vector chunks; }; @@ -66,12 +82,12 @@ RIFF::File::~File() { // protected members //////////////////////////////////////////////////////////////////////////////// -RIFF::File::File(FileName file, Endianness endianness) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(endianness)) { +RIFF::File::File(FileName file, ByteOrder endianness) : Strawberry_TagLib::TagLib::File(file), d(new FilePrivate(endianness)) { if (isOpen()) read(); } -RIFF::File::File(IOStream *stream, Endianness endianness) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate(endianness)) { +RIFF::File::File(IOStream *stream, ByteOrder endianness) : Strawberry_TagLib::TagLib::File(stream), d(new FilePrivate(endianness)) { if (isOpen()) read(); } @@ -80,8 +96,8 @@ unsigned int RIFF::File::riffSize() const { return d->size; } -unsigned int RIFF::File::chunkCount() const { - return static_cast(d->chunks.size()); +size_t RIFF::File::chunkCount() const { + return d->chunks.size(); } unsigned int RIFF::File::chunkDataSize(unsigned int i) const { @@ -95,7 +111,7 @@ unsigned int RIFF::File::chunkDataSize(unsigned int i) const { } -unsigned int RIFF::File::chunkOffset(unsigned int i) const { +long long RIFF::File::chunkOffset(unsigned int i) const { if (i >= d->chunks.size()) { debug("RIFF::File::chunkOffset() - Index out of range. Returning 0."); @@ -164,7 +180,7 @@ void RIFF::File::setChunkData(unsigned int i, const ByteVector &data) { // Now update the internal offsets for (++it; it != d->chunks.end(); ++it) - it->offset += static_cast(diff); + it->offset += diff; // Update the global size. @@ -203,7 +219,7 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bo Chunk &last = d->chunks.back(); - long offset = last.offset + last.size + last.padding; + long 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. @@ -247,7 +263,7 @@ void RIFF::File::removeChunk(unsigned int i) { std::vector::iterator it = d->chunks.begin(); std::advance(it, i); - const unsigned int removeSize = it->size + it->padding + 8; + const size_t removeSize = it->size + it->padding + 8; removeBlock(it->offset - 8, removeSize); it = d->chunks.erase(it); @@ -275,15 +291,13 @@ void RIFF::File::removeChunk(const ByteVector &name) { void RIFF::File::read() { - const bool bigEndian = (d->endianness == BigEndian); - - long offset = tell(); + long long offset = tell(); offset += 4; d->sizeOffset = offset; seek(offset); - d->size = readBlock(4).toUInt(bigEndian); + d->size = toUInt32(readBlock(4), 0, d->endianness); offset += 8; @@ -292,7 +306,7 @@ void RIFF::File::read() { seek(offset); const ByteVector chunkName = readBlock(4); - const unsigned int chunkSize = readBlock(4).toUInt(bigEndian); + const unsigned int chunkSize = toUInt32(readBlock(4), 0, d->endianness); if (!isValidChunkName(chunkName)) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID"); @@ -300,7 +314,7 @@ void RIFF::File::read() { break; } - if (static_cast(offset) + 8 + chunkSize > length()) { + if (offset + 8 + chunkSize > length()) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)"); setValid(false); break; @@ -341,12 +355,12 @@ void RIFF::File::read() { } -void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, unsigned long offset, unsigned long replace) { +void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, long long offset, size_t replace) { ByteVector combined; combined.append(name); - combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian)); + combined.append(fromUInt32(data.size(), d->endianness)); combined.append(data); if (data.size() & 1) @@ -362,7 +376,7 @@ void RIFF::File::updateGlobalSize() { 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); + const ByteVector data = fromUInt32(d->size, d->endianness); insert(data, d->sizeOffset, 4); } diff --git a/3rdparty/taglib/riff/rifffile.h b/3rdparty/taglib/riff/rifffile.h index bddb3e858..ae7e05df5 100644 --- a/3rdparty/taglib/riff/rifffile.h +++ b/3rdparty/taglib/riff/rifffile.h @@ -49,16 +49,11 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; protected: - enum Endianness { - BigEndian, - LittleEndian - }; - - explicit File(FileName file, Endianness endianness); - explicit File(IOStream *stream, Endianness endianness); + explicit File(FileName file, ByteOrder endianness); + explicit File(IOStream *stream, ByteOrder endianness); /*! * \return The size of the main RIFF chunk. @@ -68,12 +63,12 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * \return The number of chunks in the file. */ - unsigned int chunkCount() const; + size_t chunkCount() const; /*! * \return The offset within the file for the selected chunk number. */ - unsigned int chunkOffset(unsigned int i) const; + long long chunkOffset(unsigned int i) const; /*! * \return The size of the chunk data. @@ -140,11 +135,11 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { void removeChunk(const ByteVector &name); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(); - void writeChunk(const ByteVector &name, const ByteVector &data, unsigned long offset, unsigned long replace = 0); + void writeChunk(const ByteVector &name, const ByteVector &data, long long offset, size_t replace = 0); /*! * Update the global RIFF size based on the current internal structure. diff --git a/3rdparty/taglib/riff/wav/infotag.cpp b/3rdparty/taglib/riff/wav/infotag.cpp index 237ea0e6c..01a16ecd2 100644 --- a/3rdparty/taglib/riff/wav/infotag.cpp +++ b/3rdparty/taglib/riff/wav/infotag.cpp @@ -23,9 +23,11 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tdebug.h" +#include "tfile.h" +#include "tpicturemap.h" +#include "rifffile.h" #include "infotag.h" #include "riffutils.h" @@ -33,31 +35,28 @@ using namespace Strawberry_TagLib::TagLib; using namespace RIFF::Info; namespace { -const RIFF::Info::StringHandler defaultStringHandler; -const RIFF::Info::StringHandler *stringHandler = &defaultStringHandler; +class DefaultStringHandler : public Strawberry_TagLib::TagLib::StringHandler { + public: + explicit DefaultStringHandler() : Strawberry_TagLib::TagLib::StringHandler() {} + + String parse(const ByteVector &data) const override { + return String(data, String::UTF8); + } + + ByteVector render(const String &s) const override { + return s.data(String::UTF8); + } +}; + +const DefaultStringHandler defaultStringHandler; +const Strawberry_TagLib::TagLib::StringHandler *stringHandler = &defaultStringHandler; } // namespace class RIFF::Info::Tag::TagPrivate { public: - FieldListMap fieldListMap; + FieldMap fieldMap; }; -//////////////////////////////////////////////////////////////////////////////// -// StringHandler implementation -//////////////////////////////////////////////////////////////////////////////// - -StringHandler::StringHandler() {} - -StringHandler::~StringHandler() {} - -String RIFF::Info::StringHandler::parse(const ByteVector &data) const { - return String(data, String::UTF8); -} - -ByteVector RIFF::Info::StringHandler::render(const String &s) const { - return s.data(String::UTF8); -} - //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -100,6 +99,10 @@ unsigned int RIFF::Info::Tag::track() const { return fieldText("IPRT").toInt(); } +Strawberry_TagLib::TagLib::PictureMap RIFF::Info::Tag::pictures() const { + return PictureMap(); +} + void RIFF::Info::Tag::setTitle(const String &s) { setFieldText("INAM", s); } @@ -124,28 +127,30 @@ void RIFF::Info::Tag::setYear(unsigned int i) { if (i != 0) setFieldText("ICRD", String::number(i)); else - d->fieldListMap.erase("ICRD"); + d->fieldMap.erase("ICRD"); } void RIFF::Info::Tag::setTrack(unsigned int i) { if (i != 0) setFieldText("IPRT", String::number(i)); else - d->fieldListMap.erase("IPRT"); + d->fieldMap.erase("IPRT"); } +void RIFF::Info::Tag::setPictures(const PictureMap&) {} + bool RIFF::Info::Tag::isEmpty() const { - return d->fieldListMap.isEmpty(); + return d->fieldMap.isEmpty(); } -FieldListMap RIFF::Info::Tag::fieldListMap() const { - return d->fieldListMap; +FieldMap RIFF::Info::Tag::fieldMap() const { + return d->fieldMap; } String RIFF::Info::Tag::fieldText(const ByteVector &id) const { - if (d->fieldListMap.contains(id)) - return String(d->fieldListMap[id]); + if (d->fieldMap.contains(id)) + return String(d->fieldMap[id]); else return String(); @@ -158,7 +163,7 @@ void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s) { return; if (!s.isEmpty()) - d->fieldListMap[id] = s; + d->fieldMap[id] = s; else removeField(id); @@ -166,8 +171,8 @@ void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s) { void RIFF::Info::Tag::removeField(const ByteVector &id) { - if (d->fieldListMap.contains(id)) - d->fieldListMap.erase(id); + if (d->fieldMap.contains(id)) + d->fieldMap.erase(id); } @@ -175,14 +180,13 @@ ByteVector RIFF::Info::Tag::render() const { ByteVector data("INFO"); - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for (; it != d->fieldListMap.end(); ++it) { + for (FieldMap::ConstIterator it = d->fieldMap.begin(); it != d->fieldMap.end(); ++it) { ByteVector text = stringHandler->render(it->second); if (text.isEmpty()) continue; data.append(it->first); - data.append(ByteVector::fromUInt(text.size() + 1, false)); + data.append(ByteVector::fromUInt32LE(text.size() + 1)); data.append(text); do { @@ -197,7 +201,7 @@ ByteVector RIFF::Info::Tag::render() const { } -void RIFF::Info::Tag::setStringHandler(const StringHandler *handler) { +void RIFF::Info::Tag::setStringHandler(const Strawberry_TagLib::TagLib::StringHandler *handler) { if (handler) stringHandler = handler; @@ -212,16 +216,16 @@ void RIFF::Info::Tag::setStringHandler(const StringHandler *handler) { void RIFF::Info::Tag::parse(const ByteVector &data) { - unsigned int p = 4; + size_t p = 4; while (p < data.size()) { - const unsigned int size = data.toUInt(p + 4, false); + const unsigned int size = data.toUInt32LE(p + 4); if (size > data.size() - p - 8) break; const ByteVector id = data.mid(p, 4); if (isValidChunkName(id)) { const String text = stringHandler->parse(data.mid(p + 8, size)); - d->fieldListMap[id] = text; + d->fieldMap[id] = text; } p += ((size + 1) & ~1) + 8; diff --git a/3rdparty/taglib/riff/wav/infotag.h b/3rdparty/taglib/riff/wav/infotag.h index 124cf073a..61dc0f8a7 100644 --- a/3rdparty/taglib/riff/wav/infotag.h +++ b/3rdparty/taglib/riff/wav/infotag.h @@ -30,6 +30,7 @@ #include "tmap.h" #include "tstring.h" #include "tstringlist.h" +#include "tstringhandler.h" #include "tbytevector.h" #include "taglib_export.h" @@ -42,39 +43,9 @@ class File; namespace RIFF { namespace Info { -typedef Map FieldListMap; +typedef Map FieldMap; -//! A abstraction for the string to data encoding in Info tags. - -/*! - * RIFF INFO tag has no clear definitions about character encodings. - * In practice, local encoding of each system is largely used and UTF-8 is popular too. - * - * Here is an option to read and write tags in your preferred encoding by subclassing this class, - * reimplementing parse() and render() and setting your reimplementation as the default with Info::Tag::setStringHandler(). - * - * \see ID3v1::Tag::setStringHandler() - */ - -class TAGLIB_EXPORT StringHandler { - public: - explicit StringHandler(); - ~StringHandler(); - - /*! - * Decode a string from \a data. - * The default implementation assumes that \a data is an UTF-8 character array. - */ - virtual String parse(const ByteVector &data) const; - - /*! - * Encode a ByteVector with the data from \a s. - * The default implementation assumes that \a s is an UTF-8 string. - */ - virtual ByteVector render(const String &s) const; -}; - -//! The main class in the ID3v2 implementation +//! The main class in the RIFF INFO tag implementation /*! * This is the main class in the INFO tag implementation. @@ -96,27 +67,29 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { */ explicit Tag(const ByteVector &data); - virtual ~Tag(); + ~Tag() override; // Reimplementations - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; + PictureMap pictures() const override; - 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(unsigned int i); - virtual void setTrack(unsigned int i); + void setTitle(const String &s) override; + void setArtist(const String &s) override; + void setAlbum(const String &s) override; + void setComment(const String &s) override; + void setGenre(const String &s) override; + void setYear(unsigned int i) override; + void setTrack(unsigned int i) override; + void setPictures(const PictureMap&) override; - virtual bool isEmpty() const; + bool isEmpty() const override; /*! * Returns a copy of the internal fields of the tag. @@ -128,7 +101,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * \see setFieldText() * \see removeField() */ - FieldListMap fieldListMap() const; + FieldMap fieldMap() const; /* * Gets the value of the field with the ID \a id. @@ -164,9 +137,8 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { * * \note The caller is responsible for deleting the previous handler as needed after it is released. * - * \see StringHandler */ - static void setStringHandler(const StringHandler *handler); + static void setStringHandler(const Strawberry_TagLib::TagLib::StringHandler *handler); protected: /*! @@ -175,7 +147,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag { void parse(const ByteVector &data); private: - explicit Tag(const Tag&); + Tag(const Tag&); Tag &operator=(const Tag&); class TagPrivate; diff --git a/3rdparty/taglib/riff/wav/wavfile.cpp b/3rdparty/taglib/riff/wav/wavfile.cpp index e39b57e28..fabde0486 100644 --- a/3rdparty/taglib/riff/wav/wavfile.cpp +++ b/3rdparty/taglib/riff/wav/wavfile.cpp @@ -23,11 +23,13 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include +#include + +#include "tbytevector.h" +#include "tdebug.h" +#include "tstringlist.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "wavfile.h" #include "id3v2tag.h" @@ -45,14 +47,10 @@ enum { class RIFF::WAV::File::FilePrivate { public: - FilePrivate() : properties(nullptr), hasID3v2(false), hasInfo(false) {} + explicit FilePrivate() : hasID3v2(false), hasInfo(false) {} - ~FilePrivate() { - delete properties; - } - - AudioProperties *properties; - TagUnion tag; + std::unique_ptr properties; + DoubleTagUnion tag; bool hasID3v2; bool hasInfo; @@ -93,8 +91,8 @@ RIFF::WAV::File::~File() { delete d; } -ID3v2::Tag *RIFF::WAV::File::tag() const { - return ID3v2Tag(); +Strawberry_TagLib::TagLib::Tag *RIFF::WAV::File::tag() const { + return &d->tag; } ID3v2::Tag *RIFF::WAV::File::ID3v2Tag() const { @@ -117,14 +115,6 @@ void RIFF::WAV::File::strip(TagTypes tags) { } -PropertyMap RIFF::WAV::File::properties() const { - return d->tag.properties(); -} - -void RIFF::WAV::File::removeUnsupportedProperties(const StringList &properties) { - d->tag.removeUnsupportedProperties(properties); -} - PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) { InfoTag()->setProperties(properties); @@ -133,7 +123,7 @@ PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) { } RIFF::WAV::AudioProperties *RIFF::WAV::File::audioProperties() const { - return d->properties; + return d->properties.get(); } bool RIFF::WAV::File::save() { @@ -223,7 +213,7 @@ void RIFF::WAV::File::read(bool readProperties) { d->tag.set(InfoIndex, new RIFF::Info::Tag()); if (readProperties) - d->properties = new AudioProperties(this, AudioProperties::Average); + d->properties.reset(new AudioProperties(this, AudioProperties::Average)); } void RIFF::WAV::File::removeTagChunks(TagTypes tags) { diff --git a/3rdparty/taglib/riff/wav/wavfile.h b/3rdparty/taglib/riff/wav/wavfile.h index c3d01b4b2..d28482e1c 100644 --- a/3rdparty/taglib/riff/wav/wavfile.h +++ b/3rdparty/taglib/riff/wav/wavfile.h @@ -90,14 +90,14 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::RIFF::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the ID3v2 Tag for this file. * * \note This method does not return all the tags for this file for backward compatibility. Will be fixed in TagLib 2.0. */ - ID3v2::Tag *tag() const; + Strawberry_TagLib::TagLib::Tag *tag() const override; /*! * Returns the ID3v2 Tag for this file. @@ -127,30 +127,22 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::RIFF::File { */ void strip(TagTypes tags = AllTags); - /*! - * Implements the unified property interface -- export function. - * This method forwards to ID3v2::Tag::properties(). - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap &) override; /*! * Returns the WAV::AudioProperties for this file. If no audio properties * were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Saves the file. */ - virtual bool save(); + bool save() override; /*! * Save the file. @@ -181,7 +173,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::RIFF::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/riff/wav/wavproperties.cpp b/3rdparty/taglib/riff/wav/wavproperties.cpp index be2aab5a2..f2a15e9e1 100644 --- a/3rdparty/taglib/riff/wav/wavproperties.cpp +++ b/3rdparty/taglib/riff/wav/wavproperties.cpp @@ -23,7 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include +#include "tdebug.h" #include "wavfile.h" #include "wavproperties.h" @@ -39,13 +39,13 @@ enum WaveFormat { class RIFF::WAV::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : format(0), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - bitsPerSample(0), - sampleFrames(0) {} + explicit AudioPropertiesPrivate() : format(0), + length(0), + bitrate(0), + sampleRate(0), + channels(0), + bitsPerSample(0), + sampleFrames(0) {} int format; int length; @@ -60,7 +60,7 @@ class RIFF::WAV::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -Strawberry_TagLib::TagLib::RIFF::WAV::AudioProperties::AudioProperties(File *file, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style),d(new AudioPropertiesPrivate()) { +Strawberry_TagLib::TagLib::RIFF::WAV::AudioProperties::AudioProperties(File *file, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file); } @@ -126,7 +126,7 @@ void RIFF::WAV::AudioProperties::read(File *file) { } else if (name == "fact") { if (totalSamples == 0) - totalSamples = file->chunkData(i).toUInt(0, false); + totalSamples = file->chunkData(i).toUInt32LE(0); else debug("RIFF::WAV::AudioProperties::read() - Duplicate 'fact' chunk found."); } @@ -142,15 +142,15 @@ void RIFF::WAV::AudioProperties::read(File *file) { return; } - d->format = data.toShort(0, false); + d->format = data.toUInt16LE(0); if (d->format != FORMAT_PCM && totalSamples == 0) { debug("RIFF::WAV::AudioProperties::read() - Non-PCM format, but 'fact' chunk not found."); return; } - d->channels = data.toShort(2, false); - d->sampleRate = data.toUInt(4, false); - d->bitsPerSample = data.toShort(14, false); + d->channels = data.toUInt16LE(2); + d->sampleRate = data.toUInt32LE(4); + d->bitsPerSample = data.toUInt16LE(14); if (d->format != FORMAT_PCM) d->sampleFrames = totalSamples; @@ -163,7 +163,7 @@ void RIFF::WAV::AudioProperties::read(File *file) { d->bitrate = static_cast(streamLength * 8.0 / length + 0.5); } else { - const unsigned int byteRate = data.toUInt(8, false); + const unsigned int byteRate = data.toUInt32LE(8); 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 --git a/3rdparty/taglib/riff/wav/wavproperties.h b/3rdparty/taglib/riff/wav/wavproperties.h index cb010978a..e734fe101 100644 --- a/3rdparty/taglib/riff/wav/wavproperties.h +++ b/3rdparty/taglib/riff/wav/wavproperties.h @@ -51,12 +51,12 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of WAV::AudioProperties with the data read from the WAV::File \a file. */ - explicit AudioProperties(File *file, ReadStyle style); + explicit AudioProperties(File *file, ReadStyle style = Average); /*! * Destroys this WAV::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. @@ -64,29 +64,29 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -107,9 +107,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int format() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - void read(File *file); class AudioPropertiesPrivate; diff --git a/3rdparty/taglib/s3m/s3mfile.cpp b/3rdparty/taglib/s3m/s3mfile.cpp index f43bddc3f..bbe09eee5 100644 --- a/3rdparty/taglib/s3m/s3mfile.cpp +++ b/3rdparty/taglib/s3m/s3mfile.cpp @@ -65,14 +65,6 @@ Mod::Tag *S3M::File::tag() const { return &d->tag; } -PropertyMap S3M::File::properties() const { - return d->tag.properties(); -} - -PropertyMap S3M::File::setProperties(const PropertyMap &properties) { - return d->tag.setProperties(properties); -} - S3M::AudioProperties *S3M::File::audioProperties() const { return &d->properties; } diff --git a/3rdparty/taglib/s3m/s3mfile.h b/3rdparty/taglib/s3m/s3mfile.h index 96de8fe8d..898d35321 100644 --- a/3rdparty/taglib/s3m/s3mfile.h +++ b/3rdparty/taglib/s3m/s3mfile.h @@ -60,27 +60,15 @@ class TAGLIB_EXPORT File : public Mod::FileBase { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; - Mod::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * Forwards to Mod::Tag::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Forwards to Mod::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); + Mod::Tag *tag() const override; /*! * Returns the S3M::AudioProperties for this file. If no audio properties * were read then this will return a null pointer. */ - S3M::AudioProperties *audioProperties() const; + S3M::AudioProperties *audioProperties() const override; /*! * Save the file. @@ -88,10 +76,10 @@ class TAGLIB_EXPORT File : public Mod::FileBase { * * \note Saving ScreamTracker III tags is not supported. */ - bool save(); + bool save() override; private: - explicit File(const File &); + File(const File &); File &operator=(const File &); void read(bool readProperties); diff --git a/3rdparty/taglib/s3m/s3mproperties.cpp b/3rdparty/taglib/s3m/s3mproperties.cpp index 87aa46036..6bbfee83d 100644 --- a/3rdparty/taglib/s3m/s3mproperties.cpp +++ b/3rdparty/taglib/s3m/s3mproperties.cpp @@ -31,18 +31,18 @@ using namespace S3M; class S3M::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : lengthInPatterns(0), - channels(0), - stereo(false), - sampleCount(0), - patternCount(0), - flags(0), - trackerVersion(0), - fileFormatVersion(0), - globalVolume(0), - masterVolume(0), - tempo(0), - bpmSpeed(0) { + explicit AudioPropertiesPrivate() : lengthInPatterns(0), + channels(0), + stereo(false), + sampleCount(0), + patternCount(0), + flags(0), + trackerVersion(0), + fileFormatVersion(0), + globalVolume(0), + masterVolume(0), + tempo(0), + bpmSpeed(0) { } unsigned short lengthInPatterns; @@ -59,7 +59,7 @@ class S3M::AudioProperties::AudioPropertiesPrivate { unsigned char bpmSpeed; }; -S3M::AudioProperties::AudioProperties(AudioProperties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::AudioProperties(propertiesStyle), d(new AudioPropertiesPrivate()) {} +S3M::AudioProperties::AudioProperties(AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) {} S3M::AudioProperties::~AudioProperties() { delete d; @@ -129,6 +129,10 @@ unsigned char S3M::AudioProperties::bpmSpeed() const { return d->bpmSpeed; } +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + void S3M::AudioProperties::setLengthInPatterns(unsigned short lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } diff --git a/3rdparty/taglib/s3m/s3mproperties.h b/3rdparty/taglib/s3m/s3mproperties.h index 0a0e004d5..fc0ecd5d2 100644 --- a/3rdparty/taglib/s3m/s3mproperties.h +++ b/3rdparty/taglib/s3m/s3mproperties.h @@ -48,14 +48,14 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro CustomData = 128 }; - explicit AudioProperties(AudioProperties::ReadStyle propertiesStyle); - virtual ~AudioProperties(); + explicit AudioProperties(AudioProperties::ReadStyle); + ~AudioProperties() override; - int lengthInSeconds() const; - int lengthInMilliseconds() const; - int bitrate() const; - int sampleRate() const; - int channels() const; + int lengthInSeconds() const override; + int lengthInMilliseconds() const override; + int bitrate() const override; + int sampleRate() const override; + int channels() const override; unsigned short lengthInPatterns() const; bool stereo() const; @@ -69,6 +69,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro unsigned char tempo() const; unsigned char bpmSpeed() const; + private: void setChannels(int channels); void setLengthInPatterns(unsigned short lengthInPatterns); @@ -84,9 +85,6 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro void setBpmSpeed(unsigned char bpmSpeed); private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; diff --git a/3rdparty/taglib/tag.cpp b/3rdparty/taglib/tag.cpp index 3bbb495ad..70f92425e 100644 --- a/3rdparty/taglib/tag.cpp +++ b/3rdparty/taglib/tag.cpp @@ -25,6 +25,7 @@ #include "tag.h" #include "tstringlist.h" +#include "tpicturemap.h" #include "tpropertymap.h" using namespace Strawberry_TagLib::TagLib; @@ -42,7 +43,8 @@ bool Tag::isEmpty() const { comment().isEmpty() && genre().isEmpty() && year() == 0 && - track() == 0); + track() == 0 && + pictures().isEmpty()); } PropertyMap Tag::properties() const { @@ -157,6 +159,7 @@ void Tag::duplicate(const Tag *source, Tag *target, bool overwrite) { // static target->setGenre(source->genre()); target->setYear(source->year()); target->setTrack(source->track()); + target->setPictures(source->pictures()); } else { if (target->title().isEmpty()) @@ -169,10 +172,24 @@ void Tag::duplicate(const Tag *source, Tag *target, bool overwrite) { // static target->setComment(source->comment()); if (target->genre().isEmpty()) target->setGenre(source->genre()); - if (target->year() == 0) + if (target->year() <= 0) target->setYear(source->year()); - if (target->track() == 0) + if (target->track() <= 0) target->setTrack(source->track()); + if (target->pictures().isEmpty()) + target->setPictures(source->pictures()); } } + +String Tag::toString() const { + StringList desc; + desc.append("title=" + title()); + desc.append("artist=" + artist()); + desc.append("album=" + album()); + desc.append("comment=" + comment()); + desc.append("genre=" + genre()); + desc.append("year=" + String::number(year())); + desc.append("track=" + String::number(track())); + return desc.toString("\n"); +} diff --git a/3rdparty/taglib/tag.h b/3rdparty/taglib/tag.h index 76e66d586..e0a1b5239 100644 --- a/3rdparty/taglib/tag.h +++ b/3rdparty/taglib/tag.h @@ -41,6 +41,7 @@ namespace TagLib { */ class PropertyMap; +class PictureMap; class TAGLIB_EXPORT Tag { public: @@ -104,6 +105,12 @@ class TAGLIB_EXPORT Tag { */ virtual unsigned int track() const = 0; + /*! + * Returns a list of pictures available; if there is no picture, the list + * will be empty + */ + virtual PictureMap pictures() const = 0; + /*! * Sets the title to \a s. If \a s is String::null then this value will be cleared. */ @@ -141,6 +148,11 @@ class TAGLIB_EXPORT Tag { */ virtual void setTrack(unsigned int i) = 0; + /*! + * Sets the list of pictures + */ + virtual void setPictures(const PictureMap &l) = 0; + /*! * Returns true if the tag does not contain any data. * This should be reimplemented in subclasses that provide more than the basic tagging abilities in this class. @@ -160,6 +172,11 @@ class TAGLIB_EXPORT Tag { */ static void duplicate(const Tag *source, Tag *target, bool overwrite = true); + /*! + * Returns description of the tag. + */ + virtual String toString() const; + protected: /*! * Construct a Tag. This is protected since tags should only be instantiated through subclasses. @@ -167,7 +184,7 @@ class TAGLIB_EXPORT Tag { explicit Tag(); private: - explicit Tag(const Tag&); + Tag(const Tag&); Tag &operator=(const Tag&); class TagPrivate; diff --git a/3rdparty/taglib/config.h.cmake b/3rdparty/taglib/taglib-config.h.cmake similarity index 100% rename from 3rdparty/taglib/config.h.cmake rename to 3rdparty/taglib/taglib-config.h.cmake diff --git a/3rdparty/taglib/tagunion.cpp b/3rdparty/taglib/tagunion.cpp index aa33c6a5e..962e9ba78 100644 --- a/3rdparty/taglib/tagunion.cpp +++ b/3rdparty/taglib/tagunion.cpp @@ -1,4 +1,4 @@ -/*************************************************************************** +/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ @@ -23,203 +23,229 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include + #include #include #include +#include -#include "id3v1tag.h" -#include "id3v2tag.h" -#include "apetag.h" -#include "xiphcomment.h" -#include "infotag.h" - -using namespace Strawberry_TagLib::TagLib; - -#define stringUnion(method) \ - if (tag(0) && !tag(0)->method().isEmpty()) \ - return tag(0)->method(); \ - if (tag(1) && !tag(1)->method().isEmpty()) \ - return tag(1)->method(); \ - if (tag(2) && !tag(2)->method().isEmpty()) \ - return tag(2)->method(); \ +#define stringUnion(method) \ + for (size_t j = 0; j < COUNT; ++j) { \ + String val = d->tags[j] ? d->tags[j]->method() : String(); \ + if (!val.isEmpty()) \ + return val; \ + } \ return String(); -#define numberUnion(method) \ - if (tag(0) && tag(0)->method() > 0) \ - return tag(0)->method(); \ - if (tag(1) && tag(1)->method() > 0) \ - return tag(1)->method(); \ - if (tag(2) && tag(2)->method() > 0) \ - return tag(2)->method(); \ - return 0 +#define numberUnion(method) \ + for (size_t j = 0; j < COUNT; ++j) { \ + unsigned int val = d->tags[j] ? d->tags[j]->method() : 0; \ + if (val > 0) \ + return val; \ + } \ + return 0; -#define setUnion(method, value) \ - if (tag(0)) \ - tag(0)->set##method(value); \ - if (tag(1)) \ - tag(1)->set##method(value); \ - if (tag(2)) \ - tag(2)->set##method(value); +#define pictureMapUnion(method) \ + for (size_t j = 0; j < COUNT; ++j) { \ + PictureMap val = d->tags[j] ? d->tags[j]->method() : PictureMap(); \ + if (!val.isEmpty()) \ + return val; \ + } \ + return PictureMap(); -class TagUnion::TagUnionPrivate { - public: - TagUnionPrivate() : tags(3, static_cast(nullptr)) {} - - ~TagUnionPrivate() { - delete tags[0]; - delete tags[1]; - delete tags[2]; +#define setUnion(method, value) \ + for (size_t j = 0; j < COUNT; ++j) { \ + if (d->tags[j]) \ + d->tags[j]->set##method(value); \ } - std::vector tags; +namespace Strawberry_TagLib { +namespace TagLib { +template +class TagUnion::TagUnionPrivate { + public: + std::unique_ptr tags[COUNT]; }; -TagUnion::TagUnion(Tag *first, Tag *second, Tag *third) : d(new TagUnionPrivate()) { - d->tags[0] = first; - d->tags[1] = second; - d->tags[2] = third; -} +template +TagUnion::TagUnion() : d(new TagUnionPrivate()) {} -TagUnion::~TagUnion() { +template +TagUnion::~TagUnion() { delete d; } -Tag *TagUnion::operator[](int index) const { +template +Tag *TagUnion::operator[](size_t index) const { return tag(index); } -Tag *TagUnion::tag(int index) const { - return d->tags[index]; +template +Tag *TagUnion::tag(size_t index) const { + return d->tags[index].get(); } -void TagUnion::set(int index, Tag *tag) { - delete d->tags[index]; - d->tags[index] = tag; +template +void TagUnion::set(size_t index, Tag *tag) { + d->tags[index].reset(tag); } -PropertyMap TagUnion::properties() const { +template +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(); - } + for (size_t i = 0; i < COUNT; ++i) { + if (d->tags[i] && !d->tags[i]->isEmpty()) + return d->tags[i]->properties(); } return PropertyMap(); } -void TagUnion::removeUnsupportedProperties(const StringList &unsupported) { +template +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); - } + for (size_t i = 0; i < COUNT; ++i) { + if (d->tags[i]) + d->tags[i]->removeUnsupportedProperties(unsupported); } } -String TagUnion::title() const { +template +PropertyMap TagUnion::setProperties(const PropertyMap &properties) { + + // Record unassigned properties for each tag in the union + std::vector returnCandidates; + for (size_t i = 0; i < COUNT; ++i) { + if (d->tags[i]) + returnCandidates.insert(returnCandidates.end(), d->tags[i]->setProperties(properties)); + } + + if (!returnCandidates.empty()) { + // Only one tag present, return its unassigned properties + if (returnCandidates.size() == 1) { + return returnCandidates.front(); + } + + // Multiple tags in union: + // if a property has been assigned in any member tag + // remove it from ignored properties to return + PropertyMap propertiesCopy(properties); + for (std::vector::iterator i = returnCandidates.begin(); i != returnCandidates.end(); i++) { + for (PropertyMap::Iterator j = propertiesCopy.begin(); j != propertiesCopy.end();) { + if (!i->contains(j->first)) { + j = propertiesCopy.erase(j->first).begin(); + } + else { + j++; + } + } + } + } + + // No assignments made by union member tags. + // Return input (this should not happen) + return properties; +} + +template +String TagUnion::title() const { stringUnion(title); } -String TagUnion::artist() const { +template +String TagUnion::artist() const { stringUnion(artist); } -String TagUnion::album() const { +template +String TagUnion::album() const { stringUnion(album); } -String TagUnion::comment() const { +template +String TagUnion::comment() const { stringUnion(comment); } -String TagUnion::genre() const { +template +String TagUnion::genre() const { stringUnion(genre); } -unsigned int TagUnion::year() const { +template +unsigned int TagUnion::year() const { numberUnion(year); } -unsigned int TagUnion::track() const { +template +unsigned int TagUnion::track() const { numberUnion(track); } -void TagUnion::setTitle(const String &s) { +template +void TagUnion::setTitle(const String &s) { setUnion(Title, s); } -void TagUnion::setArtist(const String &s) { +template +void TagUnion::setArtist(const String &s) { setUnion(Artist, s); } -void TagUnion::setAlbum(const String &s) { +template +Strawberry_TagLib::TagLib::PictureMap TagUnion::pictures() const { + pictureMapUnion(pictures); +} + +template +void TagUnion::setAlbum(const String &s) { setUnion(Album, s); } -void TagUnion::setComment(const String &s) { +template +void TagUnion::setComment(const String &s) { setUnion(Comment, s); } -void TagUnion::setGenre(const String &s) { +template +void TagUnion::setGenre(const String &s) { setUnion(Genre, s); } -void TagUnion::setYear(unsigned int i) { +template +void TagUnion::setYear(unsigned int i) { setUnion(Year, i); } -void TagUnion::setTrack(unsigned int i) { +template +void TagUnion::setTrack(unsigned int i) { setUnion(Track, i); } -bool TagUnion::isEmpty() const { +template +void TagUnion::setPictures(const PictureMap &l) { + setUnion(Pictures, l); +} - if (d->tags[0] && !d->tags[0]->isEmpty()) - return false; - if (d->tags[1] && !d->tags[1]->isEmpty()) - return false; - if (d->tags[2] && !d->tags[2]->isEmpty()) - return false; +template +bool TagUnion::isEmpty() const { + + for (size_t i = 0; i < COUNT; ++i) { + if (d->tags[i] && !d->tags[i]->isEmpty()) + return false; + } return true; } + +// All the versions of TagUnion should be explicitly instantiated here. + +template class TagUnion<2>; +template class TagUnion<3>; + +} // namespace TagLib +} // namepsace Strawberry_TagLib diff --git a/3rdparty/taglib/tagunion.h b/3rdparty/taglib/tagunion.h index 799dea2cb..9a44f4628 100644 --- a/3rdparty/taglib/tagunion.h +++ b/3rdparty/taglib/tagunion.h @@ -26,6 +26,8 @@ #ifndef TAGLIB_TAGUNION_H #define TAGLIB_TAGUNION_H +// This file is not a part of TagLib public interface. This is not installed. + #include "tag.h" #ifndef DO_NOT_DOCUMENT @@ -34,9 +36,10 @@ namespace Strawberry_TagLib { namespace TagLib { /*! - * \internal - */ + * \internal + */ +template class TagUnion : public Tag { public: enum AccessType { @@ -45,39 +48,42 @@ class TagUnion : public Tag { }; /*! - * Creates a TagLib::Tag that is the union of \a first, \a second, and \a third. - * The TagUnion takes ownership of these tags and will handle their deletion. + * Creates a TagLib::Tag that is the union of \a count tags. */ - explicit TagUnion(Tag *first = nullptr, Tag *second = nullptr, Tag *third = nullptr); + TagUnion(); - virtual ~TagUnion(); + ~TagUnion() override; - Tag *operator[](int index) const; - Tag *tag(int index) const; + Tag *operator[](size_t index) const; + Tag *tag(size_t index) const; - void set(int index, Tag *tag); + void set(size_t index, Tag *tag); - PropertyMap properties() const; - void removeUnsupportedProperties(const StringList &unsupported); + PropertyMap properties() const override; + void removeUnsupportedProperties(const StringList &unsupported) override; + PropertyMap setProperties(const PropertyMap &properties) override; - 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; + String title() const override; + String artist() const override; + String album() const override; + String comment() const override; + String genre() const override; + unsigned int year() const override; + unsigned int track() const override; + PictureMap pictures() const override; - 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(unsigned int i); - virtual void setTrack(unsigned int i); - virtual bool isEmpty() const; + void setTitle(const String &s) override; + void setArtist(const String &s) override; + void setAlbum(const String &s) override; + void setComment(const String &s) override; + void setGenre(const String &s) override; + void setYear(unsigned int i) override; + void setTrack(unsigned int i) override; + void setPictures(const PictureMap &l) override; - template T *access(int index, bool create) { + bool isEmpty() const override; + + template T *access(size_t index, bool create) { if (!create || tag(index)) return static_cast(tag(index)); @@ -88,12 +94,14 @@ class TagUnion : public Tag { } private: - explicit TagUnion(const Tag&); - TagUnion &operator=(const Tag&); - class TagUnionPrivate; TagUnionPrivate *d; }; + +// If you add a new typedef here, add a corresponding explicit instantiation at the end of tagunion.cpp as well. + +typedef TagUnion<2> DoubleTagUnion; +typedef TagUnion<3> TripleTagUnion; } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/tagutils.cpp b/3rdparty/taglib/tagutils.cpp index b632e4f45..220ac3afb 100644 --- a/3rdparty/taglib/tagutils.cpp +++ b/3rdparty/taglib/tagutils.cpp @@ -33,13 +33,13 @@ using namespace Strawberry_TagLib::TagLib; -long Utils::findID3v1(File *file) { +long long Utils::findID3v1(File *file) { if (!file->isValid()) return -1; file->seek(-128, File::End); - const long p = file->tell(); + const long long p = file->tell(); if (file->readBlock(3) == ID3v1::Tag::fileIdentifier()) return p; @@ -48,7 +48,7 @@ long Utils::findID3v1(File *file) { } -long Utils::findID3v2(File *file) { +long long Utils::findID3v2(File *file) { if (!file->isValid()) return -1; @@ -62,7 +62,7 @@ long Utils::findID3v2(File *file) { } -long Utils::findAPE(File *file, long id3v1Location) { +long long Utils::findAPE(File *file, long long id3v1Location) { if (!file->isValid()) return -1; @@ -72,7 +72,7 @@ long Utils::findAPE(File *file, long id3v1Location) { else file->seek(-32, File::End); - const long p = file->tell(); + const long long p = file->tell(); if (file->readBlock(8) == APE::Tag::fileIdentifier()) return p; @@ -81,13 +81,13 @@ long Utils::findAPE(File *file, long id3v1Location) { } -ByteVector Strawberry_TagLib::TagLib::Utils::readHeader(IOStream *stream, unsigned int length, bool skipID3v2, long *headerOffset) { +ByteVector Strawberry_TagLib::TagLib::Utils::readHeader(IOStream *stream, size_t length, bool skipID3v2, long long *headerOffset) { if (!stream || !stream->isOpen()) return ByteVector(); - const long originalPosition = stream->tell(); - long bufferOffset = 0; + const long long originalPosition = stream->tell(); + long long bufferOffset = 0; if (skipID3v2) { stream->seek(0); diff --git a/3rdparty/taglib/tagutils.h b/3rdparty/taglib/tagutils.h index ab454777f..9d51b8cd0 100644 --- a/3rdparty/taglib/tagutils.h +++ b/3rdparty/taglib/tagutils.h @@ -40,11 +40,11 @@ class IOStream; namespace Utils { -long findID3v1(File *file); -long findID3v2(File *file); -long findAPE(File *file, long id3v1Location); +long long findID3v1(File *file); +long long findID3v2(File *file); +long long findAPE(File *file, long long id3v1Location); -ByteVector readHeader(IOStream *stream, unsigned int length, bool skipID3v2, long *headerOffset = 0); +ByteVector readHeader(IOStream *stream, size_t length, bool skipID3v2, long long *headerOffset = nullptr); } // namespace Utils } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/toolkit/taglib.cpp b/3rdparty/taglib/toolkit/taglib.cpp new file mode 100644 index 000000000..22ea58f3d --- /dev/null +++ b/3rdparty/taglib/toolkit/taglib.cpp @@ -0,0 +1,49 @@ +/*************************************************************************** + copyright : (C) 2016 by Michael Helmling + email : helmling@mathematik.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * 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 "taglib.h" +#include "tstring.h" + +using namespace Strawberry_TagLib::TagLib; + +String Strawberry_TagLib::TagLib::Version::string() { + return String::number(TAGLIB_MAJOR_VERSION) + "." + String::number(TAGLIB_MINOR_VERSION) + "." + String::number(TAGLIB_PATCH_VERSION); +} + +unsigned int Strawberry_TagLib::TagLib::Version::combined() { + return (TAGLIB_MAJOR_VERSION << 16) | (TAGLIB_MINOR_VERSION << 8) | (TAGLIB_PATCH_VERSION << 4); +} + +unsigned int(Strawberry_TagLib::TagLib::Version::major)() { + return TAGLIB_MAJOR_VERSION; +} + +unsigned int(Strawberry_TagLib::TagLib::Version::minor)() { + return TAGLIB_MINOR_VERSION; +} + +unsigned int Strawberry_TagLib::TagLib::Version::patch() { + return TAGLIB_PATCH_VERSION; +} diff --git a/3rdparty/taglib/toolkit/taglib.h b/3rdparty/taglib/toolkit/taglib.h index 6a004c66c..1cf6071fb 100644 --- a/3rdparty/taglib/toolkit/taglib.h +++ b/3rdparty/taglib/toolkit/taglib.h @@ -30,30 +30,12 @@ #define TAGLIB_MINOR_VERSION 11 #define TAGLIB_PATCH_VERSION 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 -#endif - #if (defined(_MSC_VER) && _MSC_VER >= 1600) # define TAGLIB_CONSTRUCT_BITSET(x) static_cast(x) #else # define TAGLIB_CONSTRUCT_BITSET(x) static_cast(x) #endif -#if __cplusplus >= 201402 -# define TAGLIB_DEPRECATED [[deprecated]] -#elif defined(__GNUC__) || defined(__clang__) -# define TAGLIB_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) -# define TAGLIB_DEPRECATED __declspec(deprecated) -#else -# define TAGLIB_DEPRECATED -#endif - -#include - //! A namespace for all TagLib related classes and functions /*! @@ -67,22 +49,43 @@ namespace Strawberry_TagLib { namespace TagLib { +enum ByteOrder { + LittleEndian, + BigEndian +}; + 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; +namespace Version { +/*! + * Returns the version as a string in the form + * (Major Version).(Minor Version).(Patch Version), e.g. "4.2.0". + */ +String string(); /*! - * 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; + * Returns the version as an unsigned integer in the form + * (Major Version << 16) | (Minor Version << 8) | (Patch Version), e.g. 0x040200 + * Use this for simple and consistent version comparison, e.g. + * if (TagLib::GetVersion() <= ((1 << 16) | (11 << 8))) return false; + */ +unsigned int combined(); + +/*! + * Returns the major version, e.g. 4 + */ +unsigned int(major)(); + +/*! + * Returns the minor version, e.g. 2 + */ +unsigned int(minor)(); + +/*! + * Returns the patch version, e.g. 0 + */ +unsigned int patch(); +} // namespace Version } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/toolkit/tbytevector.cpp b/3rdparty/taglib/toolkit/tbytevector.cpp index 7879714d9..e9868f762 100644 --- a/3rdparty/taglib/toolkit/tbytevector.cpp +++ b/3rdparty/taglib/toolkit/tbytevector.cpp @@ -23,6 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include #include #include #include @@ -30,10 +31,9 @@ #include #include -#include -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" +#include "tutils.h" #include "tbytevector.h" @@ -47,33 +47,33 @@ namespace Strawberry_TagLib { namespace TagLib { template -int findChar(const TIterator dataBegin, const TIterator dataEnd, char c, unsigned int offset, int byteAlign) { +size_t findChar(const TIterator dataBegin, const TIterator dataEnd, char c, size_t offset, size_t byteAlign) { const size_t dataSize = dataEnd - dataBegin; if (offset + 1 > dataSize) - return -1; + return ByteVector::npos(); // n % 0 is invalid if (byteAlign == 0) - return -1; + return ByteVector::npos(); for (TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { if (*it == c) - return static_cast(it - dataBegin); + return (it - dataBegin); } - return -1; + return ByteVector::npos(); } template -int findVector(const TIterator dataBegin, const TIterator dataEnd, const TIterator patternBegin, const TIterator patternEnd, unsigned int offset, int byteAlign) { +size_t findVector(const TIterator dataBegin, const TIterator dataEnd, const TIterator patternBegin, const TIterator patternEnd, size_t offset, size_t byteAlign) { const size_t dataSize = dataEnd - dataBegin; const size_t patternSize = patternEnd - patternBegin; if (patternSize == 0 || offset + patternSize > dataSize) - return -1; + return ByteVector::npos(); // Special case that pattern contains just single char. @@ -83,7 +83,7 @@ int findVector(const TIterator dataBegin, const TIterator dataEnd, const TIterat // n % 0 is invalid if (byteAlign == 0) - return -1; + return ByteVector::npos(); // We don't use sophisticated algorithms like Knuth-Morris-Pratt here. @@ -100,68 +100,53 @@ int findVector(const TIterator dataBegin, const TIterator dataEnd, const TIterat ++itPattern; if (itPattern == patternEnd) - return static_cast(it - dataBegin); + return (it - dataBegin); } } - return -1; + return ByteVector::npos(); } -template -T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignificantByteFirst) { +template +inline T toNumber(const ByteVector &v, size_t offset) { + if (LENGTH == sizeof(T) && offset + LENGTH <= v.size()) { + // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. + T tmp; + ::memcpy(&tmp, v.data() + offset, sizeof(T)); - if (offset >= v.size()) { - debug("toNumber() -- No data to convert. Returning 0."); + if (ENDIAN != Utils::systemByteOrder()) + return Utils::byteSwap(tmp); + else + return tmp; + } + else if (offset < v.size()) { + const size_t length = std::min(LENGTH, v.size() - offset); + T sum = 0; + for (size_t i = 0; i < length; ++i) { + const size_t shift = (ENDIAN == BigEndian ? length - 1 - i : i) * 8; + sum |= static_cast(static_cast(v[offset + i])) << shift; + } + + return sum; + } + else { + debug("toNumber() - offset is out of range. Returning 0."); return 0; } - - length = std::min(length, v.size() - offset); - - 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[static_cast(offset + i)])) << shift; - } - - return sum; - } -template -T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) { +template +inline ByteVector fromNumber(T value) { - const bool isBigEndian = (Utils::systemByteOrder() == Utils::BigEndian); - const bool swap = (mostSignificantByteFirst != isBigEndian); - - if (offset + sizeof(T) > v.size()) - return toNumber(v, offset, v.size() - offset, mostSignificantByteFirst); - - // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. - T tmp; - ::memcpy(&tmp, v.data() + offset, sizeof(T)); - - if (swap) - return Utils::byteSwap(tmp); - else - return tmp; - -} - -template -ByteVector fromNumber(T value, bool mostSignificantByteFirst) { - - const bool isBigEndian = (Utils::systemByteOrder() == Utils::BigEndian); - const bool swap = (mostSignificantByteFirst != isBigEndian); - - if (swap) + if (ENDIAN != Utils::systemByteOrder()) value = Utils::byteSwap(value); return ByteVector(reinterpret_cast(&value), sizeof(T)); } -template +template TFloat toFloat(const ByteVector &v, size_t offset) { if (offset > v.size() - sizeof(TInt)) { @@ -182,7 +167,7 @@ TFloat toFloat(const ByteVector &v, size_t offset) { } -template +template ByteVector fromFloat(TFloat value) { union { @@ -198,7 +183,7 @@ ByteVector fromFloat(TFloat value) { } -template +template long double toFloat80(const ByteVector &v, size_t offset) { using std::swap; @@ -211,7 +196,7 @@ long double toFloat80(const ByteVector &v, size_t offset) { unsigned char bytes[10]; ::memcpy(bytes, v.data() + offset, 10); - if (ENDIAN == Utils::LittleEndian) { + if (ENDIAN == LittleEndian) { swap(bytes[0], bytes[9]); swap(bytes[1], bytes[8]); swap(bytes[2], bytes[7]); @@ -249,105 +234,105 @@ long double toFloat80(const ByteVector &v, size_t offset) { class ByteVector::ByteVectorPrivate { public: - ByteVectorPrivate(unsigned int l, char c) : counter(new RefCounter()), - data(new std::vector(l, c)), - offset(0), - length(l) {} + ByteVectorPrivate() : data(new std::vector()), + offset(0), + length(0) {} - ByteVectorPrivate(const char *s, unsigned int l) : counter(new RefCounter()), - data(new std::vector(s, s + l)), - offset(0), - length(l) {} + ByteVectorPrivate(ByteVectorPrivate *d, size_t o, size_t l) : data(d->data), + offset(d->offset + o), + length(l) {} - ByteVectorPrivate(const ByteVectorPrivate &d, unsigned int o, unsigned int l) : counter(d.counter), - data(d.data), - offset(d.offset + o), - length(l) { - counter->ref(); - } + ByteVectorPrivate(size_t l, char c) : data(new std::vector(l, c)), + offset(0), + length(l) {} - ~ByteVectorPrivate() { - if (counter->deref()) { - delete counter; - delete data; - } - } + ByteVectorPrivate(const char *s, size_t l) : data(new std::vector(s, s + l)), + offset(0), + length(l) {} - RefCounter *counter; - std::vector *data; - unsigned int offset; - unsigned int length; + std::shared_ptr> data; + size_t offset; + size_t length; }; //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// -ByteVector ByteVector::fromCString(const char *s, unsigned int length) { - if (length == 0xffffffff) - return ByteVector(s, static_cast(::strlen(s))); +size_t ByteVector::npos() { + return static_cast(-1); +} + +ByteVector ByteVector::fromCString(const char *s, size_t length) { + if (length == npos()) + return ByteVector(s); else return ByteVector(s, length); } -ByteVector ByteVector::fromUInt(unsigned int value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); +ByteVector ByteVector::fromUInt16LE(size_t value) { + return fromNumber(static_cast(value)); } -ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); +ByteVector ByteVector::fromUInt16BE(size_t value) { + return fromNumber(static_cast(value)); } -ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); +ByteVector ByteVector::fromUInt32LE(size_t value) { + return fromNumber(static_cast(value)); +} + +ByteVector ByteVector::fromUInt32BE(size_t value) { + return fromNumber(static_cast(value)); +} + +ByteVector ByteVector::fromUInt64LE(unsigned long long value) { + return fromNumber(value); +} + +ByteVector ByteVector::fromUInt64BE(unsigned long long value) { + return fromNumber(value); } 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(0, '\0')) { -} +ByteVector::ByteVector() : d(new ByteVectorPrivate()) {} -ByteVector::ByteVector(unsigned int size, char value) : d(new ByteVectorPrivate(size, value)) { -} +ByteVector::ByteVector(size_t size, char value) : d(new ByteVectorPrivate(size, value)) {} -ByteVector::ByteVector(const ByteVector &v) : d(new ByteVectorPrivate(*v.d, 0, v.d->length)) { -} +ByteVector::ByteVector(const ByteVector &v) : d(new ByteVectorPrivate(*v.d)) {} -ByteVector::ByteVector(const ByteVector &v, unsigned int offset, unsigned int length) : d(new ByteVectorPrivate(*v.d, offset, length)) { -} +ByteVector::ByteVector(const ByteVector &v, size_t offset, size_t 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, unsigned int length) : d(new ByteVectorPrivate(data, length)) { -} +ByteVector::ByteVector(const char *data, size_t length) : d(new ByteVectorPrivate(data, length)) {} -ByteVector::ByteVector(const char *data) : d(new ByteVectorPrivate(data, static_cast(::strlen(data)))) { -} +ByteVector::ByteVector(const char *data) : d(new ByteVectorPrivate(data, ::strlen(data))) {} ByteVector::~ByteVector() { delete d; } -ByteVector &ByteVector::setData(const char *data, unsigned int length) { +ByteVector &ByteVector::setData(const char *data, size_t length) { ByteVector(data, length).swap(*this); return *this; } @@ -366,7 +351,7 @@ const char *ByteVector::data() const { return (size() > 0) ? (&(*d->data)[d->offset]) : nullptr; } -ByteVector ByteVector::mid(unsigned int index, unsigned int length) const { +ByteVector ByteVector::mid(size_t index, size_t length) const { index = std::min(index, size()); length = std::min(length, size() - index); @@ -375,44 +360,43 @@ ByteVector ByteVector::mid(unsigned int index, unsigned int length) const { } -char ByteVector::at(unsigned int index) const { +char ByteVector::at(size_t index) const { return (index < size()) ? (*d->data)[d->offset + index] : 0; } -int ByteVector::find(const ByteVector &pattern, unsigned int offset, int byteAlign) const { - +size_t ByteVector::find(const ByteVector &pattern, size_t offset, size_t byteAlign) const { return findVector( begin(), end(), pattern.begin(), pattern.end(), offset, byteAlign); } -int ByteVector::find(char c, unsigned int offset, int byteAlign) const { +size_t ByteVector::find(char c, size_t offset, size_t byteAlign) const { return findChar(begin(), end(), c, offset, byteAlign); } -int ByteVector::rfind(const ByteVector &pattern, unsigned int offset, int byteAlign) const { +size_t ByteVector::rfind(const ByteVector &pattern, size_t offset, size_t byteAlign) const { if (offset > 0) { offset = size() - offset - pattern.size(); if (offset >= size()) offset = 0; } - const int pos = findVector( + const size_t pos = findVector( rbegin(), rend(), pattern.rbegin(), pattern.rend(), offset, byteAlign); - if (pos == -1) - return -1; + if (pos == npos()) + return npos(); else return size() - pos - pattern.size(); } -bool ByteVector::containsAt(const ByteVector &pattern, unsigned int offset, unsigned int patternOffset, unsigned int patternLength) const { +bool ByteVector::containsAt(const ByteVector &pattern, size_t offset, size_t patternOffset, size_t 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 unsigned int compareLength = patternLength - patternOffset; + const size_t compareLength = patternLength - patternOffset; if (offset + compareLength > size() || patternOffset >= pattern.size() || patternLength == 0) return false; @@ -448,8 +432,8 @@ ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &wit // Check if there is at least one occurrence of the pattern. - int offset = find(pattern, 0); - if (offset == -1) + size_t offset = find(pattern, 0); + if (offset == ByteVector::npos()) return *this; if (pattern.size() == with.size()) { @@ -460,27 +444,27 @@ ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &wit do { ::memcpy(data() + offset, with.data(), with.size()); offset = find(pattern, offset + pattern.size()); - } while (offset != -1); + } while (offset != ByteVector::npos()); } else { // Loop once to calculate the result size. - unsigned int dstSize = size(); + size_t dstSize = size(); do { dstSize += with.size() - pattern.size(); offset = find(pattern, offset + pattern.size()); - } while (offset != -1); + } while (offset != ByteVector::npos()); // Loop again to copy modified data to the new vector. ByteVector dst(dstSize); - int dstOffset = 0; + size_t dstOffset = 0; offset = 0; while (true) { - const int next = find(pattern, offset); - if (next == -1) { + const size_t next = find(pattern, offset); + if (next == ByteVector::npos()) { ::memcpy(dst.data() + dstOffset, data() + offset, size() - offset); break; } @@ -501,23 +485,22 @@ ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &wit } -int ByteVector::endsWithPartialMatch(const ByteVector &pattern) const { +size_t ByteVector::endsWithPartialMatch(const ByteVector &pattern) const { if (pattern.size() > size()) - return -1; + return npos(); - const int startIndex = size() - pattern.size(); + const size_t startIndex = size() - pattern.size(); // 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 (unsigned int i = 1; i < pattern.size(); i++) { + for (size_t i = 1; i < pattern.size(); i++) { if (containsAt(pattern, startIndex + i, 0, pattern.size() - i)) return startIndex + i; } - return -1; - + return npos(); } ByteVector &ByteVector::append(const ByteVector &v) { @@ -527,8 +510,8 @@ ByteVector &ByteVector::append(const ByteVector &v) { detach(); - const unsigned int originalSize = size(); - const unsigned int appendSize = v.size(); + const size_t originalSize = size(); + const size_t appendSize = v.size(); resize(originalSize + appendSize); ::memcpy(data() + originalSize, v.data(), appendSize); @@ -547,11 +530,11 @@ ByteVector &ByteVector::clear() { return *this; } -unsigned int ByteVector::size() const { +size_t ByteVector::size() const { return d->length; } -ByteVector &ByteVector::resize(unsigned int size, char padding) { +ByteVector &ByteVector::resize(size_t size, char padding) { if (size != d->length) { detach(); @@ -620,71 +603,75 @@ bool ByteVector::isEmpty() const { return (d->length == 0); } -unsigned int ByteVector::toUInt(bool mostSignificantByteFirst) const { - return toNumber(*this, 0, mostSignificantByteFirst); +short ByteVector::toInt16LE(size_t offset) const { + return static_cast(toNumber(*this, offset)); } -unsigned int ByteVector::toUInt(unsigned int offset, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, mostSignificantByteFirst); +short ByteVector::toInt16BE(size_t offset) const { + return static_cast(toNumber(*this, offset)); } -unsigned int ByteVector::toUInt(unsigned int offset, unsigned int length, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, length, mostSignificantByteFirst); +unsigned short ByteVector::toUInt16LE(size_t offset) const { + return toNumber(*this, offset); } -short ByteVector::toShort(bool mostSignificantByteFirst) const { - return toNumber(*this, 0, mostSignificantByteFirst); +unsigned short ByteVector::toUInt16BE(size_t offset) const { + return toNumber(*this, offset); } -short ByteVector::toShort(unsigned int offset, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, mostSignificantByteFirst); +unsigned int ByteVector::toUInt24LE(size_t offset) const { + return toNumber(*this, offset); } -unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const { - return toNumber(*this, 0, mostSignificantByteFirst); +unsigned int ByteVector::toUInt24BE(size_t offset) const { + return toNumber(*this, offset); } -unsigned short ByteVector::toUShort(unsigned int offset, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, mostSignificantByteFirst); +unsigned int ByteVector::toUInt32LE(size_t offset) const { + return toNumber(*this, offset); } -long long ByteVector::toLongLong(bool mostSignificantByteFirst) const { - return toNumber(*this, 0, mostSignificantByteFirst); +unsigned int ByteVector::toUInt32BE(size_t offset) const { + return toNumber(*this, offset); } -long long ByteVector::toLongLong(unsigned int offset, bool mostSignificantByteFirst) const { - return toNumber(*this, offset, mostSignificantByteFirst); +long long ByteVector::toInt64LE(size_t offset) const { + return static_cast(toNumber(*this, offset)); +} + +long long ByteVector::toInt64BE(size_t offset) const { + return static_cast(toNumber(*this, offset)); } 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 { - return toFloat80(*this, offset); + return toFloat80(*this, offset); } long double ByteVector::toFloat80BE(size_t offset) const { - return toFloat80(*this, offset); + return toFloat80(*this, offset); } -const char &ByteVector::operator[](int index) const { +const char &ByteVector::operator[](size_t index) const { return (*d->data)[d->offset + index]; } -char &ByteVector::operator[](int index) { +char &ByteVector::operator[](size_t index) { detach(); return (*d->data)[d->offset + index]; } @@ -766,6 +753,7 @@ ByteVector ByteVector::toHex() const { } 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, @@ -785,7 +773,7 @@ ByteVector ByteVector::fromBase64(const ByteVector &input) { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; - unsigned int len = input.size(); + size_t len = input.size(); ByteVector output(len); @@ -840,7 +828,7 @@ ByteVector ByteVector::fromBase64(const ByteVector &input) { // Only return output if we processed all bytes if (len == 0) { - output.resize(static_cast(dst - reinterpret_cast(output.data()))); + output.resize(dst - reinterpret_cast(output.data())); return output; } return ByteVector(); @@ -850,7 +838,7 @@ ByteVector ByteVector::toBase64() const { static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; if (!isEmpty()) { - unsigned int len = size(); + size_t len = size(); ByteVector output(4 * ((len - 1) / 3 + 1)); // note roundup const char *src = data(); @@ -887,22 +875,24 @@ ByteVector ByteVector::toBase64() const { //////////////////////////////////////////////////////////////////////////////// void ByteVector::detach() { - if (d->counter->count() > 1) { + if (!d->data.unique()) { if (!isEmpty()) ByteVector(&d->data->front() + d->offset, d->length).swap(*this); else ByteVector().swap(*this); } } -} // namespace TagLib -} // namespace Strawberry_TagLib //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// -std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::ByteVector &v) { - for (unsigned int i = 0; i < v.size(); i++) +std::ostream &operator<<(std::ostream &s, const ByteVector &v) { + for (size_t i = 0; i < v.size(); i++) s << v[i]; return s; } + +} // namespace TagLib +} // namespace Strawberry_TagLib + diff --git a/3rdparty/taglib/toolkit/tbytevector.h b/3rdparty/taglib/toolkit/tbytevector.h index a540df9a6..f2bde5f6a 100644 --- a/3rdparty/taglib/toolkit/tbytevector.h +++ b/3rdparty/taglib/toolkit/tbytevector.h @@ -59,7 +59,7 @@ class TAGLIB_EXPORT ByteVector { /*! * Construct a vector of size \a size with all values set to \a value by default. */ - explicit ByteVector(unsigned int size, char value = 0); + explicit ByteVector(size_t size, char value = 0); /*! * Constructs a byte vector that is a copy of \a v. @@ -69,7 +69,7 @@ class TAGLIB_EXPORT ByteVector { /*! * Constructs a byte vector that is a copy of \a v. */ - explicit ByteVector(const ByteVector &v, unsigned int offset, unsigned int length); + explicit ByteVector(const ByteVector &v, size_t offset, size_t length); /*! * Constructs a byte vector that contains \a c. @@ -79,7 +79,7 @@ class TAGLIB_EXPORT ByteVector { /*! * Constructs a byte vector that copies \a data for up to \a length bytes. */ - explicit ByteVector(const char *data, unsigned int length); + explicit ByteVector(const char *data, size_t length); /*! * Constructs a byte vector that copies \a data up to the first null byte. @@ -97,7 +97,7 @@ class TAGLIB_EXPORT ByteVector { /*! * Sets the data for the byte array using the first \a length bytes of \a data */ - ByteVector &setData(const char *data, unsigned int length); + ByteVector &setData(const char *data, size_t length); /*! * Sets the data for the byte array copies \a data up to the first null byte. @@ -122,13 +122,13 @@ class TAGLIB_EXPORT ByteVector { * Returns a byte vector made up of the bytes starting at \a index and 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(unsigned int index, unsigned int length = 0xffffffff) const; + ByteVector mid(size_t index, size_t length = npos()) 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(unsigned int index) const; + char at(size_t index) const; /*! * Searches the ByteVector for \a pattern starting at \a offset and returns @@ -136,7 +136,7 @@ class TAGLIB_EXPORT ByteVector { * 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 find(const ByteVector &pattern, unsigned int offset = 0, int byteAlign = 1) const; + size_t find(const ByteVector &pattern, size_t offset = 0, size_t byteAlign = 1) const; /*! * Searches the char for \a c starting at \a offset and returns the offset. @@ -144,21 +144,21 @@ class TAGLIB_EXPORT ByteVector { * 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 find(char c, unsigned int offset = 0, int byteAlign = 1) const; + size_t find(char c, size_t offset = 0, size_t byteAlign = 1) const; /*! * Searches the ByteVector for \a pattern starting from either the end of the vector or \a offset and returns the offset. * Returns -1 if the pattern was 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, unsigned int offset = 0, int byteAlign = 1) const; + size_t rfind(const ByteVector &pattern, size_t offset = 0, size_t byteAlign = 1) const; /*! * Checks to see if the vector contains the \a pattern starting at position \a offset. * Optionally, if you only want to search for part of the pattern you can specify an offset within the pattern to start from. * Also, you can specify to only check for the first \a patternLength bytes of \a pattern with the \a patternLength argument. */ - bool containsAt(const ByteVector &pattern, unsigned int offset, unsigned int patternOffset = 0, unsigned int patternLength = 0xffffffff) const; + bool containsAt(const ByteVector &pattern, size_t offset, size_t patternOffset = 0, size_t patternLength = npos()) const; /*! * Returns true if the vector starts with \a pattern. @@ -188,7 +188,7 @@ class TAGLIB_EXPORT ByteVector { * * \note This will not match the complete pattern at the end of the string; use endsWith() for that. */ - int endsWithPartialMatch(const ByteVector &pattern) const; + size_t endsWithPartialMatch(const ByteVector &pattern) const; /*! * Appends \a v to the end of the ByteVector. @@ -208,14 +208,14 @@ class TAGLIB_EXPORT ByteVector { /*! * Returns the size of the array. */ - unsigned int size() const; + size_t 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(unsigned int size, char padding = 0); + ByteVector &resize(size_t size, char padding = 0); /*! * Returns an Iterator that points to the front of the vector. @@ -261,104 +261,74 @@ class TAGLIB_EXPORT ByteVector { * Returns true if the ByteVector is empty. * * \see size() - * \see isNull() */ bool isEmpty() const; /*! - * Converts the first 4 bytes of the vector to an unsigned integer. + * Converts the 2 bytes at \a offset of the vector to a short as a signed 16-bit little-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is - * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == 0x01000000 == 1. - * - * \see fromUInt() + * \see fromUInt16LE() */ - unsigned int toUInt(bool mostSignificantByteFirst = true) const; + short toInt16LE(size_t offset) const; /*! - * Converts the 4 bytes at \a offset of the vector to an unsigned integer. + * Converts the 2 bytes at \a offset of the vector to a short as a signed 16-bit big-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == 0x01000000 == 1. - * - * \see fromUInt() + * \see fromUInt16BE() */ - unsigned int toUInt(unsigned int offset, bool mostSignificantByteFirst = true) const; + short toInt16BE(size_t offset) const; /*! - * Converts the \a length bytes at \a offset of the vector to an unsigned integer. - * If \a length is larger than 4, the excess is ignored. + * Converts the 2 bytes at \a offset of the vector to a unsigned short as an unsigned 16-bit little-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == 0x01000000 == 1. - * - * \see fromUInt() + * \see fromUInt16LE() */ - unsigned int toUInt(unsigned int offset, unsigned int length, - bool mostSignificantByteFirst = true) const; + unsigned short toUInt16LE(size_t offset) const; /*! - * Converts the first 2 bytes of the vector to a (signed) short. + * Converts the 2 bytes at \a offset of the vector to a unsigned short as an unsigned 16-bit big-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() + * \see fromUInt16BE() */ - short toShort(bool mostSignificantByteFirst = true) const; + unsigned short toUInt16BE(size_t offset) const; /*! - * Converts the 2 bytes at \a offset of the vector to a (signed) short. - * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() + * Converts the 3 bytes at \a offset of the vector to a unsigned int as an unsigned 24-bit little-endian integer. */ - short toShort(unsigned int offset, bool mostSignificantByteFirst = true) const; + unsigned int toUInt24LE(size_t offset) const; /*! - * Converts the first 2 bytes of the vector to a unsigned short. - * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() + * Converts the 3 bytes at \a offset of the vector to a unsigned int as an unsigned 24-bit big-endian integer. */ - unsigned short toUShort(bool mostSignificantByteFirst = true) const; + unsigned int toUInt24BE(size_t offset) const; /*! - * Converts the 2 bytes at \a offset of the vector to a unsigned short. + * Converts the 4 bytes at \a offset of the vector to a unsigned int as an unsigned 32-bit little-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() + * \see fromUInt32LE() */ - unsigned short toUShort(unsigned int offset, bool mostSignificantByteFirst = true) const; + unsigned int toUInt32LE(size_t offset) const; /*! - * Converts the first 8 bytes of the vector to a (signed) long long. + * Converts the 4 bytes at \a offset of the vector to a unsigned int as an unsigned 32-bit big-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1, - * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. - * - * \see fromUInt() + * \see fromUInt32BE() */ - long long toLongLong(bool mostSignificantByteFirst = true) const; + unsigned int toUInt32BE(size_t offset) const; /*! - * Converts the 8 bytes at \a offset of the vector to a (signed) long long. + * Converts the 8 bytes at \a offset of the vector to a long long as a signed 64-bit little-endian integer. * - * If \a mostSignificantByteFirst is true this will operate left to right evaluating the integer. - * For example if \a mostSignificantByteFirst is true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1, - * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. - * - * \see fromUInt() + * \see fromUInt64LE() */ - long long toLongLong(unsigned int offset, bool mostSignificantByteFirst = true) const; + long long toInt64LE(size_t offset) const; + + /*! + * Converts the 8 bytes at \a offset of the vector to a long long as a signed 64-bit big-endian integer. + * + * \see fromUInt64BE() + */ + long long toInt64BE(size_t offset) const; /* * Converts the 4 bytes at \a offset of the vector to a float as an IEEE754 32-bit little-endian floating point number. @@ -395,33 +365,50 @@ class TAGLIB_EXPORT ByteVector { long double toFloat80BE(size_t offset) const; /*! - * Creates a 4 byte ByteVector based on \a value. - * If \a mostSignificantByteFirst is true, then this will operate left to right - * in building the ByteVector. - * For example if \a mostSignificantByteFirst is true then $00 00 00 01 == 0x00000001 == 1, if false, $01 00 00 00 == 0x01000000 == 1. + * Creates a 2 byte ByteVector based on \a value as an unsigned 16-bit little-endian integer. * - * \see toUInt() + * \note If \a value is larger than 16-bit, the lowest 16 bits are used. + * \see toUInt16LE() */ - static ByteVector fromUInt(unsigned int value, bool mostSignificantByteFirst = true); + static ByteVector fromUInt16LE(size_t value); /*! - * Creates a 2 byte ByteVector based on \a value. - * If \a mostSignificantByteFirst is true, then this will operate left to right in building the ByteVector. - * For example if \a mostSignificantByteFirst is true then $00 01 == 0x0001 == 1, if false, $01 00 == 0x0100 == 1. + * Creates a 2 byte ByteVector based on \a value as an unsigned 16-bit big-endian integer. * - * \see toShort() + * \note If \a value is larger than 16-bit, the lowest 16 bits are used. + * \see toUInt16BE() */ - static ByteVector fromShort(short value, bool mostSignificantByteFirst = true); + static ByteVector fromUInt16BE(size_t value); /*! - * Creates a 8 byte ByteVector based on \a value. - * If \a mostSignificantByteFirst is true, then this will operate left to right in building the ByteVector. - * For example if \a mostSignificantByteFirst is true then $00 00 00 01 == 0x0000000000000001 == 1, - * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. + * Creates a 4 byte ByteVector based on \a value as an unsigned 32-bit little-endian integer. * - * \see toLongLong() + * \note If \a value is larger than 32-bit, the lowest 32 bits are used. + * \see toUInt32LE() */ - static ByteVector fromLongLong(long long value, bool mostSignificantByteFirst = true); + static ByteVector fromUInt32LE(size_t value); + + /*! + * Creates a 4 byte ByteVector based on \a value as an unsigned 32-bit big-endian integer. + * + * \note If \a value is larger than 32-bit, the lowest 32 bits are used. + * \see toUInt32BE() + */ + static ByteVector fromUInt32BE(size_t value); + + /*! + * Creates a 8 byte ByteVector based on \a value as an unsigned 64-bit little-endian integer. + * + * \see toUInt64LE() + */ + static ByteVector fromUInt64LE(unsigned long long value); + + /*! + * Creates a 8 byte ByteVector based on \a value as an unsigned 64-bit big-endian integer. + * + * \see toUInt64BE() + */ + static ByteVector fromUInt64BE(unsigned long long value); /*! * Creates a 4 byte ByteVector based on \a value as an IEEE754 32-bit little-endian floating point number. @@ -454,17 +441,17 @@ class TAGLIB_EXPORT ByteVector { /*! * Returns a ByteVector based on the CString \a s. */ - static ByteVector fromCString(const char *s, unsigned int length = 0xffffffff); + static ByteVector fromCString(const char *s, size_t length = npos()); /*! * Returns a const reference to the byte at \a index. */ - const char &operator[](int index) const; + const char &operator[](size_t index) const; /*! * Returns a reference to the byte at \a index. */ - char &operator[](int index); + char &operator[](size_t index); /*! * Returns true if this ByteVector and \a v are equal. @@ -525,6 +512,13 @@ class TAGLIB_EXPORT ByteVector { */ void swap(ByteVector &v); + /*! + * Returns a special value used for \a length or \a patternLength parameters + * of ByteVector's member functions, means "until the end of the data". + * As a return value, it is usually used to indicate no matches. + */ + static size_t npos(); + /*! * Returns a hex-encoded copy of the byte vector. */ @@ -551,8 +545,6 @@ class TAGLIB_EXPORT ByteVector { class ByteVectorPrivate; ByteVectorPrivate *d; }; -} // namespace TagLib -} // namespace Strawberry_TagLib /*! * \relates Strawberry_TagLib::TagLib::ByteVector @@ -560,4 +552,7 @@ class TAGLIB_EXPORT ByteVector { */ TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::ByteVector &v); +} // namespace TagLib +} // namespace Strawberry_TagLib + #endif diff --git a/3rdparty/taglib/toolkit/tbytevectorlist.cpp b/3rdparty/taglib/toolkit/tbytevectorlist.cpp index 0ff240aa4..5e68605b1 100644 --- a/3rdparty/taglib/toolkit/tbytevectorlist.cpp +++ b/3rdparty/taglib/toolkit/tbytevectorlist.cpp @@ -27,18 +27,16 @@ using namespace Strawberry_TagLib::TagLib; -class ByteVectorListPrivate {}; - //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// -ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, int byteAlign, int max) { +ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, size_t byteAlign, size_t max) { ByteVectorList l; - 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)) { + size_t previousOffset = 0; + for (size_t offset = v.find(pattern, 0, byteAlign); offset != ByteVector::npos() && (max == 0 || max > l.size() + 1); offset = v.find(pattern, offset + pattern.size(), byteAlign)) { if (offset - previousOffset >= 1) l.append(v.mid(previousOffset, offset - previousOffset)); else @@ -58,9 +56,14 @@ ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &patt // public members //////////////////////////////////////////////////////////////////////////////// -ByteVectorList::ByteVectorList() : d(nullptr) {} +ByteVectorList::ByteVectorList() {} -ByteVectorList::~ByteVectorList() {} +ByteVectorList::ByteVectorList(const ByteVectorList &l) : List(l) {} + +ByteVectorList &ByteVectorList::operator=(const ByteVectorList &l) { + List::operator=(l); + return *this; +} ByteVector ByteVectorList::toByteVector(const ByteVector &separator) const { diff --git a/3rdparty/taglib/toolkit/tbytevectorlist.h b/3rdparty/taglib/toolkit/tbytevectorlist.h index d30179457..b8cd88673 100644 --- a/3rdparty/taglib/toolkit/tbytevectorlist.h +++ b/3rdparty/taglib/toolkit/tbytevectorlist.h @@ -47,9 +47,16 @@ class TAGLIB_EXPORT ByteVectorList : public List { explicit ByteVectorList(); /*! - * Destroys this ByteVectorList instance. + * Make a shallow, implicitly shared, copy of \a l. + * Because this is implicitly shared, this method is lightweight and suitable for pass-by-value usage. */ - virtual ~ByteVectorList(); + ByteVectorList(const ByteVectorList &l); + + /*! + * Make a shallow, implicitly shared, copy of \a l. + * Because this is implicitly shared, this method is lightweight and suitable for pass-by-value usage. + */ + ByteVectorList &operator=(const ByteVectorList &l); /*! * Convert the ByteVectorList to a ByteVector separated by \a separator. By default a space is used. @@ -63,11 +70,8 @@ class TAGLIB_EXPORT ByteVectorList : public List { * If \a max for instance is 2 then a maximum of 1 match will be found and the vector will be split on that match. */ - static ByteVectorList split(const ByteVector &v, const ByteVector &pattern, int byteAlign = 1, int max = 0); + static ByteVectorList split(const ByteVector &v, const ByteVector &pattern, size_t byteAlign = 1, size_t max = 0); - private: - class ByteVectorListPrivate; - ByteVectorListPrivate *d; }; } // namespace TagLib diff --git a/3rdparty/taglib/toolkit/tbytevectorstream.cpp b/3rdparty/taglib/toolkit/tbytevectorstream.cpp index 8641d54b1..7a4d2f41f 100644 --- a/3rdparty/taglib/toolkit/tbytevectorstream.cpp +++ b/3rdparty/taglib/toolkit/tbytevectorstream.cpp @@ -38,7 +38,7 @@ class ByteVectorStream::ByteVectorStreamPrivate { explicit ByteVectorStreamPrivate(const ByteVector &data); ByteVector data; - long position; + long long position; }; ByteVectorStream::ByteVectorStreamPrivate::ByteVectorStreamPrivate(const ByteVector &_data) : data(_data), position(0) {} @@ -57,7 +57,7 @@ FileName ByteVectorStream::name() const { return FileName(""); // XXX do we need a name? } -ByteVector ByteVectorStream::readBlock(unsigned long length) { +ByteVector ByteVectorStream::readBlock(size_t length) { if (length == 0) return ByteVector(); @@ -70,39 +70,39 @@ ByteVector ByteVectorStream::readBlock(unsigned long length) { void ByteVectorStream::writeBlock(const ByteVector &data) { - unsigned int size = data.size(); - if (long(d->position + size) > length()) { + const size_t size = data.size(); + if (static_cast(d->position + size) > length()) { truncate(d->position + size); } - memcpy(d->data.data() + d->position, data.data(), size); + ::memcpy(d->data.data() + d->position, data.data(), size); d->position += size; } -void ByteVectorStream::insert(const ByteVector &data, unsigned long start, unsigned long replace) { +void ByteVectorStream::insert(const ByteVector &data, long long start, size_t replace) { - long sizeDiff = data.size() - replace; - if (sizeDiff < 0) { - removeBlock(start + data.size(), -sizeDiff); + if (data.size() < replace) { + removeBlock(start + data.size(), replace - data.size()); } - else if (sizeDiff > 0) { + else if (data.size() > replace) { + const size_t sizeDiff = data.size() - replace; truncate(length() + sizeDiff); - unsigned long readPosition = start + replace; - unsigned long writePosition = start + data.size(); - memmove(d->data.data() + writePosition, d->data.data() + readPosition, length() - sizeDiff - readPosition); + const size_t readPosition = static_cast(start + replace); + const size_t writePosition = static_cast(start + data.size()); + ::memmove(d->data.data() + writePosition, d->data.data() + readPosition, static_cast(length() - sizeDiff - readPosition)); } seek(start); writeBlock(data); } -void ByteVectorStream::removeBlock(unsigned long start, unsigned long length) { +void ByteVectorStream::removeBlock(long long start, size_t length) { - 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); + const long long readPosition = start + length; + long long writePosition = start; + if (readPosition < ByteVectorStream::length()) { + size_t bytesToMove = static_cast(ByteVectorStream::length() - readPosition); + ::memmove(d->data.data() + static_cast(writePosition), d->data.data() + static_cast(readPosition), bytesToMove); writePosition += bytesToMove; } d->position = writePosition; @@ -118,7 +118,7 @@ bool ByteVectorStream::isOpen() const { return true; } -void ByteVectorStream::seek(long offset, Position p) { +void ByteVectorStream::seek(long long offset, Position p) { switch (p) { case Beginning: @@ -136,15 +136,15 @@ void ByteVectorStream::seek(long offset, Position p) { void ByteVectorStream::clear() {} -long ByteVectorStream::tell() const { +long long ByteVectorStream::tell() const { return d->position; } -long ByteVectorStream::length() { +long long ByteVectorStream::length() { return d->data.size(); } -void ByteVectorStream::truncate(long length) { +void ByteVectorStream::truncate(long long length) { d->data.resize(length); } diff --git a/3rdparty/taglib/toolkit/tbytevectorstream.h b/3rdparty/taglib/toolkit/tbytevectorstream.h index 5da5a7d2c..d0b24e0d9 100644 --- a/3rdparty/taglib/toolkit/tbytevectorstream.h +++ b/3rdparty/taglib/toolkit/tbytevectorstream.h @@ -50,17 +50,17 @@ class TAGLIB_EXPORT ByteVectorStream : public IOStream { /*! * Destroys this ByteVectorStream instance. */ - virtual ~ByteVectorStream(); + ~ByteVectorStream() override; /*! * Returns the file name in the local file system encoding. */ - FileName name() const; + FileName name() const override; /*! * Reads a block of size \a length at the current get pointer. */ - ByteVector readBlock(unsigned long length); + ByteVector readBlock(size_t length) override; /*! * Attempts to write the block \a data at the current get pointer. @@ -69,31 +69,31 @@ class TAGLIB_EXPORT ByteVectorStream : public IOStream { * \note This should be used instead of using the streaming output operator for a ByteVector. * And even this function is significantly slower than doing output with a char[]. */ - void writeBlock(const ByteVector &data); + void writeBlock(const ByteVector &data) override; /*! * Insert \a data at position \a start in the file overwriting \a replace bytes of the original content. * * \note This method is slow since it requires rewriting all of the file after the insertion point. */ - void insert(const ByteVector &data, unsigned long start = 0, unsigned long replace = 0); + void insert(const ByteVector &data, long long start = 0, size_t replace = 0) override; /*! * Removes a block of the file starting a \a start and continuing for \a length bytes. * * \note This method is slow since it involves rewriting all of the file after the removed portion. */ - void removeBlock(unsigned long start = 0, unsigned long length = 0); + void removeBlock(long long start = 0, size_t length = 0) override; /*! * Returns true if the file is read only (or if the file can not be opened). */ - bool readOnly() const; + bool readOnly() const override; /*! * Since the file can currently only be opened as an argument to the constructor (sort-of by design), this returns if that open succeeded. */ - bool isOpen() const; + bool isOpen() const override; /*! * Move the I/O pointer to \a offset in the file from position \a p. @@ -101,27 +101,27 @@ class TAGLIB_EXPORT ByteVectorStream : public IOStream { * * \see Position */ - void seek(long offset, Position p = Beginning); + void seek(long long offset, Position p = Beginning) override; /*! * Reset the end-of-file and error flags on the file. */ - void clear(); + void clear() override; /*! * Returns the current offset within the file. */ - long tell() const; + long long tell() const override; /*! * Returns the length of the file. */ - long length(); + long long length() override; /*! * Truncates the file to a \a length. */ - void truncate(long length); + void truncate(long long length) override; ByteVector *data(); diff --git a/3rdparty/taglib/toolkit/tdebug.cpp b/3rdparty/taglib/toolkit/tdebug.cpp index e17f8ccf0..5764be4c2 100644 --- a/3rdparty/taglib/toolkit/tdebug.cpp +++ b/3rdparty/taglib/toolkit/tdebug.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif +#include "taglib-config.h" #if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) diff --git a/3rdparty/taglib/toolkit/tdebuglistener.cpp b/3rdparty/taglib/toolkit/tdebuglistener.cpp index 0b5e8a4dc..398aa447d 100644 --- a/3rdparty/taglib/toolkit/tdebuglistener.cpp +++ b/3rdparty/taglib/toolkit/tdebuglistener.cpp @@ -40,7 +40,7 @@ class DefaultListener : public DebugListener { void printMessage(const String &msg) override { #ifdef _WIN32 - const wstring wstr = msg.toWString(); + const std::wstring wstr = msg.toWString(); const int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL); if (len != 0) { std::vector buf(len); diff --git a/3rdparty/taglib/toolkit/tdebuglistener.h b/3rdparty/taglib/toolkit/tdebuglistener.h index 7bb94aac0..5c6418e88 100644 --- a/3rdparty/taglib/toolkit/tdebuglistener.h +++ b/3rdparty/taglib/toolkit/tdebuglistener.h @@ -53,7 +53,7 @@ class TAGLIB_EXPORT DebugListener { private: // Noncopyable - explicit DebugListener(const DebugListener&); + DebugListener(const DebugListener&); DebugListener &operator=(const DebugListener&); }; diff --git a/3rdparty/taglib/toolkit/tfile.cpp b/3rdparty/taglib/toolkit/tfile.cpp index fa07b8557..0bad73307 100644 --- a/3rdparty/taglib/toolkit/tfile.cpp +++ b/3rdparty/taglib/toolkit/tfile.cpp @@ -28,49 +28,13 @@ #include "tstring.h" #include "tdebug.h" #include "tpropertymap.h" - -#ifdef _WIN32 -# include -# include -#else -# include -# include -#endif - -#ifndef R_OK -# define R_OK 4 -#endif -#ifndef W_OK -# define W_OK 2 -#endif - -#include "asffile.h" -#include "mpegfile.h" -#include "vorbisfile.h" -#include "flacfile.h" -#include "oggflacfile.h" -#include "mpcfile.h" -#include "mp4file.h" -#include "wavpackfile.h" -#include "speexfile.h" -#include "opusfile.h" -#include "trueaudiofile.h" -#include "aifffile.h" -#include "wavfile.h" -#include "apefile.h" -#include "modfile.h" -#include "s3mfile.h" -#include "itfile.h" -#include "xmfile.h" -#include "mp4file.h" -#include "dsffile.h" -#include "dsdifffile.h" +#include "audioproperties.h" using namespace Strawberry_TagLib::TagLib; class File::FilePrivate { public: - FilePrivate(IOStream *_stream, bool _owner) : stream(_stream), streamOwner(_owner), valid(true) {} + explicit FilePrivate(IOStream *_stream, bool _owner) : stream(_stream), streamOwner(_owner), valid(true) {} ~FilePrivate() { if (streamOwner) @@ -86,10 +50,6 @@ class File::FilePrivate { // public members //////////////////////////////////////////////////////////////////////////////// -File::File(const FileName fileName) : d(new FilePrivate(new FileStream(fileName), true)) {} - -File::File(IOStream *stream) : d(new FilePrivate(stream, false)) {} - File::~File() { delete d; } @@ -99,161 +59,45 @@ FileName File::name() const { } PropertyMap File::properties() const { - - // ugly workaround until this method is virtual - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); - if (dynamic_cast(this)) - return dynamic_cast(this)->properties(); return tag()->properties(); +} + +void File::removeUnsupportedProperties(const StringList &properties) { + tag()->removeUnsupportedProperties(properties); } -void File::removeUnsupportedProperties(const StringList& properties) { - - // here we only consider those formats that could possibly contain unsupported properties - if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if (dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else - tag()->removeUnsupportedProperties(properties); - +PropertyMap File::setProperties(const PropertyMap &properties) { + return tag()->setProperties(properties); } -PropertyMap File::setProperties(const PropertyMap& properties) { - - if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else if (dynamic_cast(this)) - return dynamic_cast(this)->setProperties(properties); - else - return tag()->setProperties(properties); - -} - -ByteVector File::readBlock(unsigned long length) { +ByteVector File::readBlock(size_t length) { return d->stream->readBlock(length); } -void File::writeBlock(const ByteVector& data) { +void File::writeBlock(const ByteVector &data) { d->stream->writeBlock(data); } -long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before) { +long long File::find(const ByteVector &pattern, long long fromOffset, const ByteVector &before) { if (!d->stream || pattern.size() > bufferSize()) return -1; // The position in the file that the current buffer starts at. - long bufferOffset = fromOffset; - ByteVector buffer; + long long bufferOffset = fromOffset; // These variables are used to keep track of a partial match that happens at // the end of a buffer. - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; + size_t previousPartialMatch = ByteVector::npos(); + size_t beforePreviousPartialMatch = ByteVector::npos(); // Save the location of the current read pointer. We will restore the // position using seek() before all returns. - long originalPosition = tell(); + long long originalPosition = tell(); // Start the search at the offset. @@ -277,20 +121,20 @@ long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &be // then check for "before". The order is important because it gives priority // to "real" matches. - for (buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { + for (ByteVector buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { // (1) previous partial match - if (previousPartialMatch >= 0 && int(bufferSize()) > previousPartialMatch) { - const int patternOffset = (bufferSize() - previousPartialMatch); + if (previousPartialMatch != ByteVector::npos() && bufferSize() > previousPartialMatch) { + const size_t patternOffset = (bufferSize() - previousPartialMatch); if (buffer.containsAt(pattern, 0, patternOffset)) { seek(originalPosition); return bufferOffset - bufferSize() + previousPartialMatch; } } - if (!before.isEmpty() && beforePreviousPartialMatch >= 0 && int(bufferSize()) > beforePreviousPartialMatch) { - const int beforeOffset = (bufferSize() - beforePreviousPartialMatch); + if (!before.isEmpty() && beforePreviousPartialMatch != ByteVector::npos() && bufferSize() > beforePreviousPartialMatch) { + const size_t beforeOffset = (bufferSize() - beforePreviousPartialMatch); if (buffer.containsAt(before, 0, beforeOffset)) { seek(originalPosition); return -1; @@ -299,13 +143,13 @@ long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &be // (2) pattern contained in current buffer - long location = buffer.find(pattern); - if (location >= 0) { + size_t location = buffer.find(pattern); + if (location != ByteVector::npos()) { seek(originalPosition); return bufferOffset + location; } - if (!before.isEmpty() && buffer.find(before) >= 0) { + if (!before.isEmpty() && buffer.find(before) != ByteVector::npos()) { seek(originalPosition); return -1; } @@ -331,35 +175,23 @@ long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &be } -long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before) { +long long File::rfind(const ByteVector &pattern, long long fromOffset, const ByteVector &before) { if (!d->stream || pattern.size() > bufferSize()) return -1; - // The position in the file that the current buffer starts at. - - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - /* - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; - */ - // Save the location of the current read pointer. We will restore the // position using seek() before all returns. - long originalPosition = tell(); + long long originalPosition = tell(); // Start the search at the offset. if (fromOffset == 0) fromOffset = length(); - long bufferLength = bufferSize(); - long bufferOffset = fromOffset + pattern.size(); + long long bufferLength = bufferSize(); + long long bufferOffset = fromOffset + pattern.size(); // See the notes in find() for an explanation of this algorithm. @@ -374,7 +206,7 @@ long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &b } seek(bufferOffset); - buffer = readBlock(bufferLength); + const ByteVector buffer = readBlock(static_cast(bufferLength)); if (buffer.isEmpty()) break; @@ -382,13 +214,13 @@ long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &b // (2) pattern contained in current buffer - const long location = buffer.rfind(pattern); - if (location >= 0) { + const size_t location = buffer.rfind(pattern); + if (location != ByteVector::npos()) { seek(originalPosition); return bufferOffset + location; } - if (!before.isEmpty() && buffer.find(before) >= 0) { + if (!before.isEmpty() && buffer.find(before) != ByteVector::npos()) { seek(originalPosition); return -1; } @@ -406,11 +238,11 @@ long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &b } -void File::insert(const ByteVector& data, unsigned long start, unsigned long replace) { +void File::insert(const ByteVector &data, long long start, size_t replace) { d->stream->insert(data, start, replace); } -void File::removeBlock(unsigned long start, unsigned long length) { +void File::removeBlock(long long start, size_t length) { d->stream->removeBlock(start, length); } @@ -426,11 +258,11 @@ bool File::isValid() const { return isOpen() && d->valid; } -void File::seek(long offset, Position p) { +void File::seek(long long offset, Position p) { d->stream->seek(offset, IOStream::Position(p)); } -void File::truncate(long length) { +void File::truncate(long long length) { d->stream->truncate(length); } @@ -438,20 +270,40 @@ void File::clear() { d->stream->clear(); } -long File::tell() const { +long long File::tell() const { return d->stream->tell(); } -long File::length() { +long long File::length() { return d->stream->length(); } +String File::toString() const { + + StringList desc; + AudioProperties *properties = audioProperties(); + if (properties) { + desc.append(properties->toString()); + } + Tag *t = tag(); + if (t) { + desc.append(t->toString()); + } + return desc.toString("\n"); + +} + + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// -unsigned int File::bufferSize() { - return 1024; +File::File(const FileName &fileName) : d(new FilePrivate(new FileStream(fileName), true)) {} + +File::File(IOStream *stream) : d(new FilePrivate(stream, false)) {} + +size_t File::bufferSize() { + return FileStream::bufferSize(); } void File::setValid(bool valid) { diff --git a/3rdparty/taglib/toolkit/tfile.h b/3rdparty/taglib/toolkit/tfile.h index eabbc97e2..4743ba43a 100644 --- a/3rdparty/taglib/toolkit/tfile.h +++ b/3rdparty/taglib/toolkit/tfile.h @@ -150,7 +150,7 @@ class TAGLIB_EXPORT File { /*! * Reads a block of size \a length at the current get pointer. */ - ByteVector readBlock(unsigned long length); + ByteVector readBlock(size_t length); /*! * Attempts to write the block \a data at the current get pointer. @@ -171,7 +171,7 @@ class TAGLIB_EXPORT File { * \note This has the practical limitation that \a pattern can not be longer * than the buffer size used by readBlock(). Currently this is 1024 bytes. */ - long find(const ByteVector &pattern, long fromOffset = 0, const ByteVector &before = ByteVector()); + long long find(const ByteVector &pattern, long long fromOffset = 0, const ByteVector &before = ByteVector()); /*! * Returns the offset in the file that \a pattern occurs at or -1 if it can not be found. @@ -184,21 +184,21 @@ class TAGLIB_EXPORT File { * \note This has the practical limitation that \a pattern can not be longer * than the buffer size used by readBlock(). Currently this is 1024 bytes. */ - long rfind(const ByteVector &pattern, long fromOffset = 0, const ByteVector &before = ByteVector()); + long long rfind(const ByteVector &pattern, long long fromOffset = 0, const ByteVector &before = ByteVector()); /*! * Insert \a data at position \a start in the file overwriting \a replace bytes of the original content. * * \note This method is slow since it requires rewriting all of the file after the insertion point. */ - void insert(const ByteVector &data, unsigned long start = 0, unsigned long replace = 0); + void insert(const ByteVector &data, long long start = 0, size_t replace = 0); /*! * Removes a block of the file starting a \a start and continuing for \a length bytes. * * \note This method is slow since it involves rewriting all of the file after the removed portion. */ - void removeBlock(unsigned long start = 0, unsigned long length = 0); + void removeBlock(long long start = 0, size_t length = 0); /*! * Returns true if the file is read only (or if the file can not be opened). @@ -222,7 +222,7 @@ class TAGLIB_EXPORT File { * * \see Position */ - void seek(long offset, Position p = Beginning); + void seek(long long offset, Position p = Beginning); /*! * Reset the end-of-file and error flags on the file. @@ -232,12 +232,17 @@ class TAGLIB_EXPORT File { /*! * Returns the current offset within the file. */ - long tell() const; + long long tell() const; /*! * Returns the length of the file. */ - long length(); + long long length(); + + /*! + * Returns description of the audio file and its tags. + */ + virtual String toString() const; protected: /*! @@ -246,7 +251,7 @@ class TAGLIB_EXPORT File { * * \note Constructor is protected since this class should only be instantiated through subclasses. */ - explicit File(const FileName fileName); + explicit File(const FileName &fileName); /*! * Construct a File object and use the \a stream instance. @@ -267,15 +272,15 @@ class TAGLIB_EXPORT File { /*! * Truncates the file to a \a length. */ - void truncate(long length); + void truncate(long long length); /*! * Returns the buffer size that is used for internal buffering. */ - static unsigned int bufferSize(); + static size_t bufferSize(); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); class FilePrivate; diff --git a/3rdparty/taglib/toolkit/tfilestream.cpp b/3rdparty/taglib/toolkit/tfilestream.cpp index 1209378eb..975c754a8 100644 --- a/3rdparty/taglib/toolkit/tfilestream.cpp +++ b/3rdparty/taglib/toolkit/tfilestream.cpp @@ -51,9 +51,9 @@ FileHandle openFile(const FileName &path, bool readOnly) { const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); # if defined(PLATFORM_WINRT) - return CreateFile2(path.wstr().c_str(), access, FILE_SHARE_READ, OPEN_EXISTING, NULL); + return CreateFile2(path.wstr(), access, FILE_SHARE_READ, OPEN_EXISTING, NULL); # else - return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + return CreateFileW(path.wstr(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); # endif } @@ -149,7 +149,7 @@ FileStream::FileStream(FileName fileName, bool openReadOnly) if (d->file == InvalidFileHandle) #ifdef _WIN32 - debug("Could not open file " + fileName.toString()); + debug("Could not open file " + String(fileName.wstr())); #else debug("Could not open file " + String(static_cast(d->name))); #endif @@ -186,7 +186,7 @@ FileName FileStream::name() const { return d->name; } -ByteVector FileStream::readBlock(unsigned long length) { +ByteVector FileStream::readBlock(size_t length) { if (!isOpen()) { debug("FileStream::readBlock() -- invalid file."); @@ -196,14 +196,14 @@ ByteVector FileStream::readBlock(unsigned long length) { if (length == 0) return ByteVector(); - const unsigned long streamLength = static_cast(FileStream::length()); - if (length > bufferSize() && length > streamLength) + const long long streamLength = FileStream::length(); + if (length > bufferSize() && static_cast(length) > streamLength) length = streamLength; - ByteVector buffer(static_cast(length)); + ByteVector buffer(length); const size_t count = readFile(d->file, buffer); - buffer.resize(static_cast(count)); + buffer.resize(count); return buffer; @@ -225,7 +225,7 @@ void FileStream::writeBlock(const ByteVector &data) { } -void FileStream::insert(const ByteVector &data, unsigned long start, unsigned long replace) { +void FileStream::insert(const ByteVector &data, long long start, size_t replace) { if (!isOpen()) { debug("FileStream::insert() -- invalid file."); @@ -259,18 +259,18 @@ void FileStream::insert(const ByteVector &data, unsigned long start, unsigned lo // the *difference* in the tag sizes. We want to avoid overwriting parts // that aren't yet in memory, so this is necessary. - unsigned long bufferLength = bufferSize(); + size_t bufferLength = bufferSize(); while (data.size() - replace > bufferLength) bufferLength += bufferSize(); // Set where to start the reading and writing. - long readPosition = start + replace; - long writePosition = start; + long long readPosition = start + replace; + long long writePosition = start; ByteVector buffer = data; - ByteVector aboutToOverwrite(static_cast(bufferLength)); + ByteVector aboutToOverwrite(bufferLength); while (true) { // Seek to the current read position and read the data that we're about @@ -307,19 +307,19 @@ void FileStream::insert(const ByteVector &data, unsigned long start, unsigned lo } -void FileStream::removeBlock(unsigned long start, unsigned long length) { +void FileStream::removeBlock(long long start, size_t length) { if (!isOpen()) { debug("FileStream::removeBlock() -- invalid file."); return; } - unsigned long bufferLength = bufferSize(); + size_t bufferLength = bufferSize(); - long readPosition = start + length; - long writePosition = start; + long long readPosition = start + length; + long long writePosition = start; - ByteVector buffer(static_cast(bufferLength)); + ByteVector buffer(bufferLength, 0); for (unsigned int bytesRead = -1; bytesRead != 0;) { seek(readPosition); @@ -352,7 +352,7 @@ bool FileStream::isOpen() const { return (d->file != InvalidFileHandle); } -void FileStream::seek(long offset, Position p) { +void FileStream::seek(long long offset, Position p) { if (!isOpen()) { debug("FileStream::seek() -- invalid file."); @@ -391,7 +391,7 @@ void FileStream::seek(long offset, Position p) { return; } - fseek(d->file, offset, whence); + fseeko(d->file, offset, whence); #endif @@ -409,15 +409,14 @@ void FileStream::clear() { #endif } -long FileStream::tell() const { +long long FileStream::tell() const { #ifdef _WIN32 const LARGE_INTEGER zero = {}; LARGE_INTEGER position; - if (SetFilePointerEx(d->file, zero, &position, FILE_CURRENT) && - position.QuadPart <= LONG_MAX) { - return static_cast(position.QuadPart); + if (SetFilePointerEx(d->file, zero, &position, FILE_CURRENT)) { + return position.QuadPart; } else { debug("FileStream::tell() -- Failed to get the file pointer."); @@ -426,12 +425,12 @@ long FileStream::tell() const { #else - return ftell(d->file); + return ftello(d->file); #endif } -long FileStream::length() { +long long FileStream::length() { if (!isOpen()) { debug("FileStream::length() -- invalid file."); @@ -442,8 +441,8 @@ long FileStream::length() { LARGE_INTEGER fileSize; - if (GetFileSizeEx(d->file, &fileSize) && fileSize.QuadPart <= LONG_MAX) { - return static_cast(fileSize.QuadPart); + if (GetFileSizeEx(d->file, &fileSize)) { + return fileSize.QuadPart; } else { debug("FileStream::length() -- Failed to get the file size."); @@ -452,10 +451,10 @@ long FileStream::length() { #else - const long curpos = tell(); + const long long curpos = tell(); seek(0, End); - const long endpos = tell(); + const long long endpos = tell(); seek(curpos, Beginning); @@ -464,14 +463,18 @@ long FileStream::length() { #endif } +size_t FileStream::bufferSize() { + return 1024; +} + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// -void FileStream::truncate(long length) { +void FileStream::truncate(long long length) { #ifdef _WIN32 - const long currentPos = tell(); + const long long currentPos = tell(); seek(length); @@ -491,6 +494,3 @@ void FileStream::truncate(long length) { #endif } -unsigned int FileStream::bufferSize() { - return 1024; -} diff --git a/3rdparty/taglib/toolkit/tfilestream.h b/3rdparty/taglib/toolkit/tfilestream.h index 57058b391..b08731b9e 100644 --- a/3rdparty/taglib/toolkit/tfilestream.h +++ b/3rdparty/taglib/toolkit/tfilestream.h @@ -61,17 +61,17 @@ class TAGLIB_EXPORT FileStream : public IOStream { /*! * Destroys this FileStream instance. */ - virtual ~FileStream(); + ~FileStream() override; /*! * Returns the file name in the local file system encoding. */ - FileName name() const; + FileName name() const override; /*! * Reads a block of size \a length at the current get pointer. */ - ByteVector readBlock(unsigned long length); + ByteVector readBlock(size_t length) override; /*! * Attempts to write the block \a data at the current get pointer. @@ -80,14 +80,14 @@ class TAGLIB_EXPORT FileStream : public IOStream { * \note This should be used instead of using the streaming output operator for a ByteVector. * And even this function is significantly slower than doing output with a char[]. */ - void writeBlock(const ByteVector &data); + void writeBlock(const ByteVector &data) override; /*! * Insert \a data at position \a start in the file overwriting \a replace bytes of the original content. * * \note This method is slow since it requires rewriting all of the file after the insertion point. */ - void insert(const ByteVector &data, unsigned long start = 0, unsigned long replace = 0); + void insert(const ByteVector &data, long long start = 0, size_t replace = 0) override; /*! * Removes a block of the file starting a \a start and continuing for \a length bytes. @@ -95,17 +95,17 @@ class TAGLIB_EXPORT FileStream : public IOStream { * \note This method is slow since it involves rewriting all of the file * after the removed portion. */ - void removeBlock(unsigned long start = 0, unsigned long length = 0); + void removeBlock(long long start = 0, size_t length = 0) override; /*! * Returns true if the file is read only (or if the file can not be opened). */ - bool readOnly() const; + bool readOnly() const override; /*! * Since the file can currently only be opened as an argument to the constructor (sort-of by design), this returns if that open succeeded. */ - bool isOpen() const; + bool isOpen() const override; /*! * Move the I/O pointer to \a offset in the file from position \a p. @@ -113,33 +113,32 @@ class TAGLIB_EXPORT FileStream : public IOStream { * * \see Position */ - void seek(long offset, Position p = Beginning); + void seek(long long offset, Position p = Beginning) override; /*! * Reset the end-of-file and error flags on the file. */ - void clear(); + void clear() override; /*! * Returns the current offset within the file. */ - long tell() const; + long long tell() const override; /*! * Returns the length of the file. */ - long length(); + long long length() override; /*! * Truncates the file to a \a length. */ - void truncate(long length); + void truncate(long long length) override; - protected: /*! * Returns the buffer size that is used for internal buffering. */ - static unsigned int bufferSize(); + static size_t bufferSize(); private: class FileStreamPrivate; diff --git a/3rdparty/taglib/toolkit/tiostream.cpp b/3rdparty/taglib/toolkit/tiostream.cpp index f8b40a006..745005e56 100644 --- a/3rdparty/taglib/toolkit/tiostream.cpp +++ b/3rdparty/taglib/toolkit/tiostream.cpp @@ -24,8 +24,9 @@ ***************************************************************************/ #ifdef _WIN32 +# include # include -# include +# include "tstring.h" #endif #include "tiostream.h" @@ -49,32 +50,36 @@ std::wstring ansiToUnicode(const char *str) { } } // namespace -// m_name is no longer used, but kept for backward compatibility. +class FileName::FileNamePrivate { + public: + FileNamePrivate() : data(new std::wstring()) {} -FileName::FileName(const wchar_t *name) : m_name(), m_wname(name) {} + FileNamePrivate(const wchar_t *name) : data(new std::wstring(name)) {} -FileName::FileName(const char *name) : m_name(), m_wname(ansiToUnicode(name)) {} + FileNamePrivate(const char *name) : data(new std::wstring(ansiToUnicode(name))) {} -FileName::FileName(const FileName &name) : m_name(), m_wname(name.m_wname) {} + std::shared_ptr data; +}; -FileName::operator const wchar_t *() const { - return m_wname.c_str(); +FileName::FileName(const wchar_t *name) : d(new FileNamePrivate(name)) {} + +FileName::FileName(const char *name) : d(new FileNamePrivate(name)) {} + +FileName::FileName(const FileName &name) : d(new FileNamePrivate()) { + *d = *name.d; } -FileName::operator const char *() const { - return m_name.c_str(); +FileName::~FileName() { + delete d; } -const std::wstring &FileName::wstr() const { - return m_wname; +FileName &FileName::operator=(const FileName &name) { + *d = *name.d; + return *this; } -const std::string &FileName::str() const { - return m_name; -} - -String FileName::toString() const { - return String(m_wname.c_str()); +const wchar_t *FileName::wstr() const { + return d->data->c_str(); } #endif // _WIN32 diff --git a/3rdparty/taglib/toolkit/tiostream.h b/3rdparty/taglib/toolkit/tiostream.h index fd7178de6..987c2b68f 100644 --- a/3rdparty/taglib/toolkit/tiostream.h +++ b/3rdparty/taglib/toolkit/tiostream.h @@ -34,24 +34,24 @@ namespace Strawberry_TagLib { namespace TagLib { #ifdef _WIN32 + +class String; + class TAGLIB_EXPORT FileName { public: FileName(const wchar_t *name); FileName(const char *name); - FileName(const FileName &name); - operator const wchar_t *() const; - operator const char *() const; + ~FileName(); - const std::wstring &wstr() const; - const std::string &str() const; + FileName &operator=(const FileName &name); - String toString() const; + const wchar_t *wstr() const; private: - const std::string m_name; - const std::wstring m_wname; + class FileNamePrivate; + FileNamePrivate *d; }; #else typedef const char *FileName; @@ -88,7 +88,7 @@ class TAGLIB_EXPORT IOStream { /*! * Reads a block of size \a length at the current get pointer. */ - virtual ByteVector readBlock(unsigned long length) = 0; + virtual ByteVector readBlock(size_t length) = 0; /*! * Attempts to write the block \a data at the current get pointer. @@ -105,14 +105,14 @@ class TAGLIB_EXPORT IOStream { * \note This method is slow since it requires rewriting all of the file after the insertion point. */ virtual void insert(const ByteVector &data, - unsigned long start = 0, unsigned long replace = 0) = 0; + long long start = 0, size_t replace = 0) = 0; /*! * Removes a block of the file starting a \a start and continuing for \a length bytes. * * \note This method is slow since it involves rewriting all of the file after the removed portion. */ - virtual void removeBlock(unsigned long start = 0, unsigned long length = 0) = 0; + virtual void removeBlock(long long start = 0, size_t length = 0) = 0; /*! * Returns true if the file is read only (or if the file can not be opened). @@ -130,7 +130,7 @@ class TAGLIB_EXPORT IOStream { * * \see Position */ - virtual void seek(long offset, Position p = Beginning) = 0; + virtual void seek(long long offset, Position p = Beginning) = 0; /*! * Reset the end-of-stream and error flags on the stream. @@ -140,20 +140,20 @@ class TAGLIB_EXPORT IOStream { /*! * Returns the current offset within the stream. */ - virtual long tell() const = 0; + virtual long long tell() const = 0; /*! * Returns the length of the stream. */ - virtual long length() = 0; + virtual long long length() = 0; /*! * Truncates the stream to a \a length. */ - virtual void truncate(long length) = 0; + virtual void truncate(long long length) = 0; private: - explicit IOStream(const IOStream&); + IOStream(const IOStream&); IOStream &operator=(const IOStream&); }; diff --git a/3rdparty/taglib/toolkit/tlist.h b/3rdparty/taglib/toolkit/tlist.h index 0238fcab0..0585b3862 100644 --- a/3rdparty/taglib/toolkit/tlist.h +++ b/3rdparty/taglib/toolkit/tlist.h @@ -28,6 +28,7 @@ #include "taglib.h" +#include #include namespace Strawberry_TagLib { @@ -141,7 +142,7 @@ template class List { * * \see isEmpty() */ - unsigned int size() const; + size_t size() const; /*! * Returns whether or not the list is empty. @@ -153,17 +154,20 @@ template class List { /*! * Find the first occurrence of \a value. */ - Iterator find(const T &value); + template + Iterator find(const U &value); /*! * Find the first occurrence of \a value. */ - ConstIterator find(const T &value) const; + template + ConstIterator find(const U &value) const; /*! * Returns true if the list contains \a value. */ - bool contains(const T &value) const; + template + bool contains(const U &value) const; /*! * Erase the item at \a it from the list. @@ -203,14 +207,14 @@ template class List { * * \warning This method is slow. Use iterators to loop through the list. */ - T &operator[](unsigned int i); + T &operator[](size_t 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[](unsigned int i) const; + const T &operator[](size_t i) const; /*! * Make a shallow, implicitly shared, copy of \a l. diff --git a/3rdparty/taglib/toolkit/tlist.tcc b/3rdparty/taglib/toolkit/tlist.tcc index d6ba68f4e..16b9cd6f5 100644 --- a/3rdparty/taglib/toolkit/tlist.tcc +++ b/3rdparty/taglib/toolkit/tlist.tcc @@ -36,50 +36,59 @@ namespace TagLib { // The functionality of List::setAutoDelete() is implemented here partial template specialization. // This is implemented in such a way that calling setAutoDelete() on non-pointer types will simply have no effect. -// A base for the generic and specialized private class types. -// New non-templatized members should be added here. - -// BIC change to RefCounter -class ListPrivateBase : public RefCounterOld { -public: - ListPrivateBase() : autoDelete(false) {} - bool autoDelete; -}; - // A generic implementation template -template class List::ListPrivate : public ListPrivateBase +template class List::ListPrivate : public RefCounter { public: - explicit ListPrivate() : ListPrivateBase() {} - explicit ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} + explicit ListPrivate() {} + explicit ListPrivate(const std::list &l) : list(l) {} + void clear() { - list.clear(); + std::list().swap(list); } + + void setAutoDelete(bool) {} + std::list list; }; // A partial specialization for all pointer types that implements the setAutoDelete() functionality. template -template class List::ListPrivate : public ListPrivateBase +template class List::ListPrivate : public RefCounter { public: - explicit ListPrivate() : ListPrivateBase() {} - explicit ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} - ~ListPrivate() { - clear(); + explicit ListPrivate() : autoDelete(false) {} + + explicit ListPrivate(const std::list &l) : list(l), autoDelete(false) {} + + ~ListPrivate() override { + deletePointers(); } + void clear() { + deletePointers(); + std::list().swap(list); + } + + void setAutoDelete(bool del) { + autoDelete = del; + } + + std::list list; + +private: + void deletePointers() { if(autoDelete) { typename std::list::const_iterator it = list.begin(); for(; it != list.end(); ++it) delete *it; } - list.clear(); } - std::list list; + + bool autoDelete; }; //////////////////////////////////////////////////////////////////////////////// @@ -124,60 +133,74 @@ typename List::ConstIterator List::end() const { template typename List::Iterator List::insert(Iterator it, const T &item) { + detach(); return d->list.insert(it, item); + } template List &List::sortedInsert(const T &value, bool unique) { + detach(); Iterator it = begin(); - while(it != end() && *it < value) + while (it != end() && *it < value) ++it; - if(unique && it != end() && *it == value) + if (unique && it != end() && *it == value) return *this; insert(it, value); return *this; + } template List &List::append(const T &item) { + detach(); d->list.push_back(item); return *this; + } template List &List::append(const List &l) { + detach(); d->list.insert(d->list.end(), l.begin(), l.end()); return *this; + } template List &List::prepend(const T &item) { + detach(); d->list.push_front(item); return *this; + } template List &List::prepend(const List &l) { + detach(); d->list.insert(d->list.begin(), l.begin(), l.end()); return *this; + } template List &List::clear() { + detach(); d->clear(); return *this; + } template -unsigned int List::size() const { - return static_cast(d->list.size()); +size_t List::size() const { + return d->list.size(); } template @@ -186,18 +209,21 @@ bool List::isEmpty() const { } template -typename List::Iterator List::find(const T &value) { +template +typename List::Iterator List::find(const U &value) { detach(); return std::find(d->list.begin(), d->list.end(), value); } template -typename List::ConstIterator List::find(const T &value) const { +template +typename List::ConstIterator List::find(const U &value) const { return std::find(d->list.begin(), d->list.end(), value); } template -bool List::contains(const T &value) const { +template +bool List::contains(const U &value) const { return std::find(d->list.begin(), d->list.end(), value) != d->list.end(); } @@ -224,42 +250,51 @@ const T &List::back() const { template void List::setAutoDelete(bool autoDelete) { - d->autoDelete = autoDelete; + d->setAutoDelete(autoDelete); } template T &List::back() { + detach(); return d->list.back(); + } template -T &List::operator[](unsigned int i) { +T &List::operator[](size_t i) { + Iterator it = d->list.begin(); std::advance(it, i); return *it; + } template -const T &List::operator[](unsigned int i) const { +const T &List::operator[](size_t i) const { + ConstIterator it = d->list.begin(); std::advance(it, i); return *it; + } template List &List::operator=(const List &l) { + List(l).swap(*this); return *this; + } template void List::swap(List &l) { - using std::swap; + using std::swap; swap(d, l.d); + } template @@ -278,10 +313,12 @@ bool List::operator!=(const List &l) const { template void List::detach() { - if(d->count() > 1) { + + if (!d->unique()) { d->deref(); d = new ListPrivate(d->list); } + } } } // namespace Strawberry_TagLib::TagLib diff --git a/3rdparty/taglib/toolkit/tmap.h b/3rdparty/taglib/toolkit/tmap.h index afa06ce29..7e7c4991e 100644 --- a/3rdparty/taglib/toolkit/tmap.h +++ b/3rdparty/taglib/toolkit/tmap.h @@ -26,6 +26,7 @@ #ifndef TAGLIB_MAP_H #define TAGLIB_MAP_H +#include #include #include "taglib.h" @@ -41,7 +42,7 @@ namespace TagLib { */ template class Map { - public: + private: #ifndef DO_NOT_DOCUMENT # ifdef WANT_CLASS_INSTANTIATION_OF_MAP // Some STL implementations get snippy over the use of the class keyword to distinguish different templates; Sun Studio @@ -49,14 +50,18 @@ template class Map { // GCC doesn't seem to mind, and uses the typedefs further below without the class keyword. // Not all the specializations of Map can use the class keyword (when T is not actually a class type), // so don't apply this generally. - typedef typename std::map::iterator Iterator; - typedef typename std::map::const_iterator ConstIterator; + typedef std::map MapType; # else - typedef typename std::map::iterator Iterator; - typedef typename std::map::const_iterator ConstIterator; + typedef std::map MapType; # endif #endif + public: +#ifndef DO_NOT_DOCUMENT + typedef typename MapType::iterator Iterator; + typedef typename MapType::const_iterator ConstIterator; +#endif + /*! * Constructs an empty Map. */ @@ -114,7 +119,7 @@ template class Map { * * \see isEmpty() */ - unsigned int size() const; + size_t size() const; /*! * Returns true if the map is empty. diff --git a/3rdparty/taglib/toolkit/tmap.tcc b/3rdparty/taglib/toolkit/tmap.tcc index d81549f37..d2a16ebf4 100644 --- a/3rdparty/taglib/toolkit/tmap.tcc +++ b/3rdparty/taglib/toolkit/tmap.tcc @@ -32,19 +32,14 @@ namespace TagLib { // public members //////////////////////////////////////////////////////////////////////////////// -// BIC change to RefCounter template template -class Map::MapPrivate : public RefCounterOld { -public: - explicit MapPrivate() : RefCounterOld() {} -#ifdef WANT_CLASS_INSTANTIATION_OF_MAP - explicit MapPrivate(const std::map& m) : RefCounterOld(), map(m) {} - std::map map; -#else - explicit MapPrivate(const std::map& m) : RefCounterOld(), map(m) {} - std::map map; -#endif +class Map::MapPrivate : public RefCounter { + public: + explicit MapPrivate() : RefCounter() {} + explicit MapPrivate(const MapType &m) : RefCounter(), map(m) {} + + MapType map; }; template @@ -133,8 +128,8 @@ Map &Map::erase(const Key &key) { } template -unsigned int Map::size() const { - return static_cast(d->map.size()); +size_t Map::size() const { + return d->map.size(); } template @@ -167,7 +162,7 @@ void Map::swap(Map &m) { template void Map::detach() { - if(d->count() > 1) { + if (!d->unique()) { d->deref(); d = new MapPrivate(d->map); } diff --git a/3rdparty/taglib/toolkit/tpicture.cpp b/3rdparty/taglib/toolkit/tpicture.cpp new file mode 100644 index 000000000..56ddf03f2 --- /dev/null +++ b/3rdparty/taglib/toolkit/tpicture.cpp @@ -0,0 +1,179 @@ +/*************************************************************************** + copyright : (C) 2015 by Maxime Leblanc + email : lblnc.maxime@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 + +#include "tpicture.h" + +using namespace Strawberry_TagLib::TagLib; + +namespace { +struct PictureData { + explicit PictureData() : type(Picture::Other) {} + + ByteVector data; + Picture::Type type; + String mime; + String description; +}; +} // namespace + +class Picture::PicturePrivate { + public: + explicit PicturePrivate() : data(new PictureData()) {} + + std::shared_ptr data; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Picture::Picture() : d(new PicturePrivate()) {} + +Picture::Picture(const ByteVector &data, Type type, const String &mime, const String &description) : d(new PicturePrivate()) { + + d->data->data = data; + d->data->type = type; + d->data->mime = mime; + d->data->description = description; + +} + +Picture::Picture(const Picture &p) : d(new PicturePrivate(*p.d)) {} + +Picture::~Picture() { + delete d; +} + +String Picture::description() const { + return d->data->description; +} + +ByteVector Picture::data() const { + return d->data->data; +} + +String Picture::mime() const { + return d->data->mime; +} + +Picture::Type Picture::type() const { + return d->data->type; +} + +void Picture::swap(Picture &other) { + using std::swap; + + swap(d, other.d); +} + +/* =========== OPERATORS =========== */ + +Picture &Picture::operator=(const Picture &p) { + Picture(p).swap(*this); + return *this; +} + +std::ostream &operator<<(std::ostream &s, const Picture &p) { + + String type; + switch (p.type()) { + case Picture::FileIcon: + type = "FileIcon"; + break; + case Picture::OtherFileIcon: + type = "OtherFileIcon"; + break; + case Picture::FrontCover: + type = "FrontCover"; + break; + case Picture::BackCover: + type = "BackCover"; + break; + case Picture::LeafletPage: + type = "LeafletPage"; + break; + case Picture::Media: + type = "Media"; + break; + case Picture::LeadArtist: + type = "LeadArtist"; + break; + case Picture::Artist: + type = "Artist"; + break; + case Picture::Conductor: + type = "Conductor"; + break; + case Picture::Band: + type = "Band"; + break; + case Picture::Composer: + type = "Composer"; + break; + case Picture::Lyricist: + type = "Lyricist"; + break; + case Picture::RecordingLocation: + type = "RecordingLocation"; + break; + case Picture::DuringRecording: + type = "DuringRecording"; + break; + case Picture::DuringPerformance: + type = "DuringPerformance"; + break; + case Picture::MovieScreenCapture: + type = "MovieScreenCapture"; + break; + case Picture::ColouredFish: + type = "ColouredFish"; + break; + case Picture::Illustration: + type = "Illustration"; + break; + case Picture::BandLogo: + type = "BandLogo"; + break; + case Picture::PublisherLogo: + type = "PublisherLogo"; + break; + default: + type = "Other"; + break; + } + + ByteVector displayableData = p.data().mid(0, 20).toHex(); + s << "\nPicture:\n" + << "\ttype: " << type.to8Bit() << std::endl + << "\tdesc: " << p.description().to8Bit() << std::endl + << "\tmime: " << p.mime().to8Bit() << std::endl + << "\tdata: " << std::hex << displayableData << "..." << std::endl; + + return s; + +} diff --git a/3rdparty/taglib/toolkit/tpicture.h b/3rdparty/taglib/toolkit/tpicture.h new file mode 100644 index 000000000..9220c1cf4 --- /dev/null +++ b/3rdparty/taglib/toolkit/tpicture.h @@ -0,0 +1,157 @@ +/*************************************************************************** + copyright : (C) 2015 by Maxime Leblanc + email : lblnc.maxime@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_PICTURE_H +#define TAGLIB_PICTURE_H + +#include "taglib_export.h" +#include "tbytevector.h" +#include "tmap.h" +#include "tstring.h" + +namespace Strawberry_TagLib { +namespace TagLib { + +class TAGLIB_EXPORT Picture { + + class PicturePrivate; + + public: + /*! + * The Type enum is based on types in id3v2 tags + */ + enum Type { + //! A type not enumerated below + Other = 0x00, + //! 32x32 PNG image that should be used as the file icon + FileIcon = 0x01, + //! File icon of a different size or format + OtherFileIcon = 0x02, + //! Front cover image of the album + FrontCover = 0x03, + //! Back cover image of the album + BackCover = 0x04, + //! Inside leaflet page of the album + LeafletPage = 0x05, + //! Image from the album itself + Media = 0x06, + //! Picture of the lead artist or soloist + LeadArtist = 0x07, + //! Picture of the artist or performer + Artist = 0x08, + //! Picture of the conductor + Conductor = 0x09, + //! Picture of the band or orchestra + Band = 0x0A, + //! Picture of the composer + Composer = 0x0B, + //! Picture of the lyricist or text writer + Lyricist = 0x0C, + //! Picture of the recording location or studio + RecordingLocation = 0x0D, + //! Picture of the artists during recording + DuringRecording = 0x0E, + //! Picture of the artists during performance + DuringPerformance = 0x0F, + //! Picture from a movie or video related to the track + MovieScreenCapture = 0x10, + //! Picture of a large, coloured fish + ColouredFish = 0x11, + //! Illustration related to the track + Illustration = 0x12, + //! Logo of the band or performer + BandLogo = 0x13, + //! Logo of the publisher (record company) + PublisherLogo = 0x14 + }; + + /*! + * Constructs an empty Picture. + */ + explicit Picture(); + + /*! + * Constructs a Picture object base on an other Picture + */ + Picture(const Picture &p); + + /*! + * Constructs a Picture object based on the \a ByteVector given. + * + * \note type, mime and description are optional + */ + explicit Picture(const ByteVector &data, Type type = Other, const String &mime = "image/", const String &description = String()); + + /*! + * Destroys this Picture instance. + */ + virtual ~Picture(); + + /*! + * Returns the mime of the picture + */ + String mime() const; + + /*! + * Returns the description of the picture + */ + String description() const; + + /*! + * Returns the type of the picture + */ + Type type() const; + + /*! + * Returns data of the picture + */ + ByteVector data() const; + + /*! + * Performs a shallow, implicitly shared, copy of \a p, overwriting the + * Picture's current data. + */ + Picture &operator=(const Picture &p); + + /*! + * Exchanges the content of the Picture by the content of \a p. + */ + void swap(Picture &p); + + private: + PicturePrivate *d; +}; + +} // namespace TagLib +} // namespace Strawberry_TagLib + +/*! + * \relates TagLib::Picture + * + * Send the picture to an output stream. + */ +TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::Picture &picture); + +#endif // TAGLIB_PICTUREMAP_H diff --git a/3rdparty/taglib/toolkit/tpicturemap.cpp b/3rdparty/taglib/toolkit/tpicturemap.cpp new file mode 100644 index 000000000..db3083844 --- /dev/null +++ b/3rdparty/taglib/toolkit/tpicturemap.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + copyright : (C) 2015 by Maxime Leblanc + email : lblnc.maxime@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 "tpicturemap.h" + +using namespace Strawberry_TagLib::TagLib; + +PictureMap::PictureMap() : Map() {} + +PictureMap::PictureMap(const PictureList &l) : Map() { + insert(l); +} + +PictureMap::PictureMap(const Picture &p) : Map() { + insert(p); +} + +void PictureMap::insert(const Picture &p) { + + PictureList list; + if (contains(p.type())) { + list = Map::find(p.type())->second; + list.append(p); + Map::insert(p.type(), list); + } + else { + list.append(p); + Map::insert(p.type(), list); + } + +} + +void PictureMap::insert(const PictureList &l) { + + for (PictureList::ConstIterator it = l.begin(); it != l.end(); ++it) { + Picture picture = (*it); + insert(picture); + } + +} + +PictureMap::~PictureMap() {} + +std::ostream &operator<<(std::ostream &s, const PictureMap &map) { + + for (PictureMap::ConstIterator it = map.begin(); it != map.end(); ++it) { + PictureList list = it->second; + for (PictureList::ConstIterator it2 = list.begin(); it2 != list.end(); ++it2) + s << *it2; + } + return s; + +} diff --git a/3rdparty/taglib/toolkit/tpicturemap.h b/3rdparty/taglib/toolkit/tpicturemap.h new file mode 100644 index 000000000..18cdaec90 --- /dev/null +++ b/3rdparty/taglib/toolkit/tpicturemap.h @@ -0,0 +1,89 @@ +/*************************************************************************** + copyright : (C) 2015 by Maxime Leblanc + email : lblnc.maxime@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_PICTUREMAP_H +#define TAGLIB_PICTUREMAP_H + +#include "tlist.h" +#include "tmap.h" +#include "taglib_export.h" +#include "tpicture.h" + +namespace Strawberry_TagLib { +namespace TagLib { + +//! A list of pictures +typedef List PictureList; + +/// TODO: review this interface before the release of TagLib v2.x in light of +/// https://github.com/taglib/taglib/issues/734#issuecomment-214001325 + +/*! + * This is a spcialization of the List class with some members. + */ +class TAGLIB_EXPORT PictureMap : public Map { + public: + /*! + * Constructs an empty PictureList. + */ + explicit PictureMap(); + + /*! + * Constructs a PictureMap with \a Picture. + */ + explicit PictureMap(const Picture &p); + + /*! + * Constructs a PictureMap with \a PictureList as a member. + */ + explicit PictureMap(const PictureList &l); + + /*! + * Destroys this PictureList instance. + */ + ~PictureMap() override; + + /*! + * Inserts a PictureList into the picture map + */ + void insert(const PictureList &l); + + /*! + * Inserts a Picture into the picture map + */ + void insert(const Picture &p); +}; + +} // namespace TagLib +} // namespace Strawberry_TagLib + +/*! + * \relates TagLib::PictureMap + * + * Send the PictureMap to on output stream + */ +TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::PictureMap &map); + +#endif // TAGLIB_PICTUREMAP_H diff --git a/3rdparty/taglib/toolkit/tpropertymap.h b/3rdparty/taglib/toolkit/tpropertymap.h index 2e67de019..9cd984b35 100644 --- a/3rdparty/taglib/toolkit/tpropertymap.h +++ b/3rdparty/taglib/toolkit/tpropertymap.h @@ -116,7 +116,7 @@ class TAGLIB_EXPORT PropertyMap : public SimplePropertyMap { */ PropertyMap(const SimplePropertyMap &m); - virtual ~PropertyMap(); + ~PropertyMap() override; /*! * Inserts \a values under \a key in the map. diff --git a/3rdparty/taglib/toolkit/trefcounter.cpp b/3rdparty/taglib/toolkit/trefcounter.cpp index 5f3c4fd79..13e7d4b04 100644 --- a/3rdparty/taglib/toolkit/trefcounter.cpp +++ b/3rdparty/taglib/toolkit/trefcounter.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif +#include "taglib-config.h" #include "trefcounter.h" @@ -36,26 +34,26 @@ # define ATOMIC_DEC(x) (--(x)) #elif defined(HAVE_GCC_ATOMIC) # define ATOMIC_INT int -# define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) -# define ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +# define ATOMIC_INC(x) ::__sync_add_and_fetch(&x, 1) +# define ATOMIC_DEC(x) ::__sync_sub_and_fetch(&x, 1) #elif defined(HAVE_WIN_ATOMIC) # if !defined(NOMINMAX) # define NOMINMAX # endif # include -# define ATOMIC_INT long -# define ATOMIC_INC(x) InterlockedIncrement(&x) -# define ATOMIC_DEC(x) InterlockedDecrement(&x) +# define ATOMIC_INT volatile LONG +# define ATOMIC_INC(x) ::InterlockedIncrement(&x) +# define ATOMIC_DEC(x) ::InterlockedDecrement(&x) #elif defined(HAVE_MAC_ATOMIC) # include # define ATOMIC_INT int32_t -# define ATOMIC_INC(x) OSAtomicIncrement32Barrier(&x) -# define ATOMIC_DEC(x) OSAtomicDecrement32Barrier(&x) +# define ATOMIC_INC(x) ::OSAtomicIncrement32Barrier(&x) +# define ATOMIC_DEC(x) ::OSAtomicDecrement32Barrier(&x) #elif defined(HAVE_IA64_ATOMIC) # include # define ATOMIC_INT int -# define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) -# define ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +# define ATOMIC_INC(x) ::__sync_add_and_fetch(&x, 1) +# define ATOMIC_DEC(x) ::__sync_sub_and_fetch(&x, 1) #else # define ATOMIC_INT int # define ATOMIC_INC(x) (++(x)) @@ -69,7 +67,7 @@ class RefCounter::RefCounterPrivate { public: RefCounterPrivate() : refCount(1) {} - volatile ATOMIC_INT refCount; + ATOMIC_INT refCount; }; RefCounter::RefCounter() : d(new RefCounterPrivate()) {} @@ -89,5 +87,9 @@ bool RefCounter::deref() { int RefCounter::count() const { return static_cast(d->refCount); } + +bool RefCounter::unique() const { + return (d->refCount == 1); +} } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/toolkit/trefcounter.h b/3rdparty/taglib/toolkit/trefcounter.h index 8147bc198..26b7c9802 100644 --- a/3rdparty/taglib/toolkit/trefcounter.h +++ b/3rdparty/taglib/toolkit/trefcounter.h @@ -29,23 +29,6 @@ #include "taglib_export.h" #include "taglib.h" -#ifdef __APPLE__ -# define OSATOMIC_DEPRECATED 0 -# include -# define TAGLIB_ATOMIC_MAC -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include -# define TAGLIB_ATOMIC_WIN -#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) && (defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64) || defined(__ia64)) && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -#elif defined(__ia64) && defined(__INTEL_COMPILER) -# include -# define TAGLIB_ATOMIC_GCC -#endif - #ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. /*! * \internal @@ -64,56 +47,16 @@ class TAGLIB_EXPORT RefCounter { void ref(); bool deref(); int count() const; + bool unique() const; private: + RefCounter(const RefCounter&); + RefCounter &operator=(const RefCounter&); + class RefCounterPrivate; RefCounterPrivate *d; }; -// BIC this old class is needed by tlist.tcc and tmap.tcc -class RefCounterOld { - public: - explicit RefCounterOld() : refCount(1) {} - -# ifdef TAGLIB_ATOMIC_MAC - void ref() { - OSAtomicIncrement32Barrier(const_cast(&refCount)); - } - bool deref() { return !OSAtomicDecrement32Barrier(const_cast(&refCount)); } - int32_t count() { return refCount; } - - private: - volatile int32_t refCount; -# elif defined(TAGLIB_ATOMIC_WIN) - void ref() { - InterlockedIncrement(&refCount); - } - bool deref() { return !InterlockedDecrement(&refCount); } - long count() { return refCount; } - - private: - volatile long refCount; -# elif defined(TAGLIB_ATOMIC_GCC) - void ref() { - __sync_add_and_fetch(&refCount, 1); - } - bool deref() { return !__sync_sub_and_fetch(&refCount, 1); } - int count() { return refCount; } - - private: - volatile int refCount; -# else - void ref() { - refCount++; - } - bool deref() { return !--refCount; } - int count() { return refCount; } - - private: - unsigned int refCount; -# endif -}; - } // namespace TagLib } // namespace Strawberry_TagLib diff --git a/3rdparty/taglib/toolkit/tstring.cpp b/3rdparty/taglib/toolkit/tstring.cpp index 061730427..2606225cd 100644 --- a/3rdparty/taglib/toolkit/tstring.cpp +++ b/3rdparty/taglib/toolkit/tstring.cpp @@ -23,15 +23,15 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include #include #include #include -#include -#include -#include -#include +#include "tdebug.h" +#include "tstringlist.h" +#include "tutils.h" #include "tstring.h" @@ -41,7 +41,7 @@ using namespace Strawberry_TagLib::TagLib; // Returns the native format of std::wstring. String::Type wcharByteOrder() { - if (Utils::systemByteOrder() == Utils::LittleEndian) + if (Utils::systemByteOrder() == LittleEndian) return String::UTF16LE; else return String::UTF16BE; @@ -143,21 +143,29 @@ void copyFromUTF16(std::wstring &data, const T *s, size_t length, String::Type t namespace Strawberry_TagLib { namespace TagLib { -class String::StringPrivate : public RefCounter { +class String::StringPrivate { public: - StringPrivate() {} + StringPrivate() : data(new std::wstring()) {} /*! * Stores string in UTF-16. The byte order depends on the CPU endian. */ - Strawberry_TagLib::TagLib::wstring data; + std::shared_ptr data; /*! * This is only used to hold the the most recent value of toCString(). */ - std::string cstring; + std::shared_ptr cstring; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +size_t String::npos() { + return std::wstring::npos; +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -165,52 +173,40 @@ class String::StringPrivate : public RefCounter { String::String() : d(new StringPrivate()) { } -String::String(const String &s) : d(s.d) { - d->ref(); -} +String::String(const String &s) : d(new StringPrivate(*s.d)) {} String::String(const std::string &s, Type t) : d(new StringPrivate()) { if (t == Latin1) - copyFromLatin1(d->data, s.c_str(), s.length()); + copyFromLatin1(*d->data, s.c_str(), s.length()); else if (t == String::UTF8) - copyFromUTF8(d->data, 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 std::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(); - else if (t == UTF16LE) - t = (wcharByteOrder() == UTF16LE ? UTF16BE : UTF16LE); + if (t == UTF16Native) + t = wcharByteOrder(); - copyFromUTF16(d->data, s.c_str(), s.length(), t); - } + if (t == UTF16 || t == UTF16BE || t == UTF16LE) + copyFromUTF16(*d->data, s.c_str(), s.length(), t); else { - debug("String::String() -- TagLib::wstring should not contain Latin1 or UTF-8."); + debug("String::String() -- std::wstring should not contain Latin1 or UTF-8."); } } 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(); - else if (t == UTF16LE) - t = (wcharByteOrder() == UTF16LE ? UTF16BE : UTF16LE); + if (t == UTF16Native) + t = wcharByteOrder(); - copyFromUTF16(d->data, s, ::wcslen(s), t); - } + if (t == UTF16 || t == UTF16BE || t == UTF16LE) + copyFromUTF16(*d->data, s, ::wcslen(s), t); else { debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8."); } @@ -220,9 +216,9 @@ String::String(const wchar_t *s, Type t) : d(new StringPrivate()) { String::String(const char *s, Type t) : d(new StringPrivate()) { if (t == Latin1) - copyFromLatin1(d->data, s, ::strlen(s)); + copyFromLatin1(*d->data, s, ::strlen(s)); else if (t == String::UTF8) - copyFromUTF8(d->data, s, ::strlen(s)); + copyFromUTF8(*d->data, s, ::strlen(s)); else { debug("String::String() -- const char * should not contain UTF16."); } @@ -231,8 +227,11 @@ String::String(const char *s, Type t) : d(new StringPrivate()) { String::String(wchar_t c, Type t) : d(new StringPrivate()) { + if (t == UTF16Native) + t = wcharByteOrder(); + if (t == UTF16 || t == UTF16BE || t == UTF16LE) - copyFromUTF16(d->data, &c, 1, t); + copyFromUTF16(*d->data, &c, 1, t); else { debug("String::String() -- wchar_t should not contain Latin1 or UTF-8."); } @@ -242,9 +241,9 @@ String::String(wchar_t c, Type t) : d(new StringPrivate()) { String::String(char c, Type t) : d(new StringPrivate()) { if (t == Latin1) - copyFromLatin1(d->data, &c, 1); + copyFromLatin1(*d->data, &c, 1); else if (t == String::UTF8) - copyFromUTF8(d->data, &c, 1); + copyFromUTF8(*d->data, &c, 1); else { debug("String::String() -- char should not contain UTF16."); } @@ -256,23 +255,25 @@ String::String(const ByteVector &v, Type t) : d(new StringPrivate()) { if (v.isEmpty()) return; + if (t == UTF16Native) + t = wcharByteOrder(); + if (t == Latin1) - copyFromLatin1(d->data, v.data(), v.size()); + copyFromLatin1(*d->data, v.data(), v.size()); else if (t == UTF8) - copyFromUTF8(d->data, v.data(), v.size()); + copyFromUTF8(*d->data, v.data(), v.size()); else - copyFromUTF16(d->data, v.data(), v.size() / 2, t); + copyFromUTF16(*d->data, v.data(), v.size() / 2, t); // If we hit a null in the ByteVector, shrink the string again. - d->data.resize(::wcslen(d->data.c_str())); + d->data->resize(::wcslen(d->data->c_str())); } //////////////////////////////////////////////////////////////////////////////// String::~String() { - if (d->deref()) - delete d; + delete d; } std::string String::to8Bit(bool unicode) const { @@ -282,51 +283,51 @@ std::string String::to8Bit(bool unicode) const { } -Strawberry_TagLib::TagLib::wstring String::toWString() const { - return d->data; +const std::wstring &String::toWString() const { + return *d->data; } const char *String::toCString(bool unicode) const { - d->cstring = to8Bit(unicode); - return d->cstring.c_str(); + d->cstring.reset(new std::string(to8Bit(unicode))); + return d->cstring->c_str(); } const wchar_t *String::toCWString() const { - return d->data.c_str(); + return d->data->c_str(); } String::Iterator String::begin() { detach(); - return d->data.begin(); + return d->data->begin(); } String::ConstIterator String::begin() const { - return d->data.begin(); + return d->data->begin(); } String::Iterator String::end() { detach(); - return d->data.end(); + return d->data->end(); } String::ConstIterator String::end() const { - return d->data.end(); + return d->data->end(); } -int String::find(const String &s, int offset) const { - return static_cast(d->data.find(s.d->data, offset)); +size_t String::find(const String &s, size_t offset) const { + return d->data->find(*s.d->data, offset); } -int String::rfind(const String &s, int offset) const { - return static_cast(d->data.rfind(s.d->data, offset)); +size_t String::rfind(const String &s, size_t offset) const { + return d->data->rfind(*s.d->data, offset); } StringList String::split(const String &separator) const { StringList list; - for (int index = 0;;) { - int sep = find(separator, index); - if (sep < 0) { + for (size_t index = 0;;) { + const size_t sep = find(separator, index); + if (sep == npos()) { list.append(substr(index, size() - index)); break; } @@ -346,19 +347,18 @@ bool String::startsWith(const String &s) const { return substr(0, s.length()) == s; } -String String::substr(unsigned int position, unsigned int n) const { +String String::substr(size_t position, size_t length) const { - if (position == 0 && n >= size()) + if (position == 0 && length >= size()) return *this; else - return String(d->data.substr(position, n)); - + return String(d->data->substr(position, length)); } String &String::append(const String &s) { detach(); - d->data += s.d->data; + *d->data += *s.d->data; return *this; } @@ -373,29 +373,29 @@ String &String::clear() { String String::upper() const { String s; - s.d->data.reserve(size()); + s.d->data->reserve(size()); for (ConstIterator it = begin(); it != end(); ++it) { if (*it >= 'a' && *it <= 'z') - s.d->data.push_back(*it + 'A' - 'a'); + s.d->data->push_back(*it + 'A' - 'a'); else - s.d->data.push_back(*it); + s.d->data->push_back(*it); } return s; } -unsigned int String::size() const { - return static_cast(d->data.size()); +size_t String::size() const { + return d->data->size(); } -unsigned int String::length() const { +size_t String::length() const { return size(); } bool String::isEmpty() const { - return d->data.empty(); + return d->data->empty(); } ByteVector String::data(Type t) const { @@ -472,7 +472,7 @@ ByteVector String::data(Type t) const { int String::toInt(bool *ok) const { - const wchar_t *begin = d->data.c_str(); + const wchar_t *begin = d->data->c_str(); wchar_t *end; errno = 0; const long value = ::wcstol(begin, &end, 10); @@ -491,12 +491,12 @@ String String::stripWhiteSpace() const { static const wchar_t *WhiteSpaceChars = L"\t\n\f\r "; - const size_t pos1 = d->data.find_first_not_of(WhiteSpaceChars); + const size_t pos1 = d->data->find_first_not_of(WhiteSpaceChars); if (pos1 == std::wstring::npos) return String(); - const size_t pos2 = d->data.find_last_not_of(WhiteSpaceChars); - return substr(static_cast(pos1), static_cast(pos2 - pos1 + 1)); + const size_t pos2 = d->data->find_last_not_of(WhiteSpaceChars); + return substr(pos1, pos2 - pos1 + 1); } @@ -524,17 +524,17 @@ String String::number(int n) { // static return Utils::formatString("%d", n); } -wchar_t &String::operator[](int i) { +wchar_t &String::operator[](size_t i) { detach(); - return d->data[i]; + return (*d->data)[i]; } -const wchar_t &String::operator[](int i) const { - return d->data[i]; +const wchar_t &String::operator[](size_t i) const { + return (*d->data)[i]; } bool String::operator==(const String &s) const { - return (d == s.d || d->data == s.d->data); + return (d->data == s.d->data || *d->data == *s.d->data); } bool String::operator!=(const String &s) const { @@ -558,7 +558,7 @@ bool String::operator!=(const char *s) const { } bool String::operator==(const wchar_t *s) const { - return (d->data == s); + return (*d->data == s); } bool String::operator!=(const wchar_t *s) const { @@ -568,14 +568,14 @@ bool String::operator!=(const wchar_t *s) const { String &String::operator+=(const String &s) { detach(); - d->data += s.d->data; + *d->data += *s.d->data; return *this; } String &String::operator+=(const wchar_t *s) { detach(); - d->data += s; + *d->data += s; return *this; } @@ -583,21 +583,22 @@ String &String::operator+=(const char *s) { detach(); for (int i = 0; s[i] != 0; i++) - d->data += static_cast(s[i]); + *d->data += static_cast(s[i]); + return *this; } String &String::operator+=(wchar_t c) { detach(); - d->data += c; + *d->data += c; return *this; } String &String::operator+=(char c) { detach(); - d->data += static_cast(c); + *d->data += static_cast(c); return *this; } @@ -611,7 +612,7 @@ String &String::operator=(const std::string &s) { return *this; } -String &String::operator=(const wstring &s) { +String &String::operator=(const std::wstring &s) { String(s).swap(*this); return *this; } @@ -627,7 +628,7 @@ String &String::operator=(char c) { } String &String::operator=(wchar_t c) { - String(c, wcharByteOrder()).swap(*this); + String(c).swap(*this); return *this; } @@ -648,7 +649,7 @@ void String::swap(String &s) { } bool String::operator<(const String &s) const { - return (d->data < s.d->data); + return (*d->data < *s.d->data); } //////////////////////////////////////////////////////////////////////////////// @@ -656,30 +657,27 @@ bool String::operator<(const String &s) const { //////////////////////////////////////////////////////////////////////////////// void String::detach() { - if (d->count() > 1) - String(d->data.c_str()).swap(*this); + if (!d->data.unique()) + String(d->data->c_str()).swap(*this); } -} // namespace TagLib -} // namespace Strawberry_TagLib - //////////////////////////////////////////////////////////////////////////////// // related non-member functions //////////////////////////////////////////////////////////////////////////////// -const Strawberry_TagLib::TagLib::String operator+(const Strawberry_TagLib::TagLib::String &s1, const Strawberry_TagLib::TagLib::String &s2) { +const String operator+(const String &s1, const String &s2) { Strawberry_TagLib::TagLib::String s(s1); s.append(s2); return s; } -const Strawberry_TagLib::TagLib::String operator+(const char *s1, const Strawberry_TagLib::TagLib::String &s2) { +const String operator+(const char *s1, const String &s2) { Strawberry_TagLib::TagLib::String s(s1); s.append(s2); return s; } -const Strawberry_TagLib::TagLib::String operator+(const Strawberry_TagLib::TagLib::String &s1, const char *s2) { +const String operator+(const String &s1, const char *s2) { Strawberry_TagLib::TagLib::String s(s1); s.append(s2); return s; @@ -689,3 +687,7 @@ std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::Strin s << str.to8Bit(); return s; } + +} // namespace TagLib +} // namespace Strawberry_TagLib + diff --git a/3rdparty/taglib/toolkit/tstring.h b/3rdparty/taglib/toolkit/tstring.h index cd1d2ae23..b0941f57c 100644 --- a/3rdparty/taglib/toolkit/tstring.h +++ b/3rdparty/taglib/toolkit/tstring.h @@ -69,7 +69,7 @@ class StringList; /*! * This is an implicitly shared \e wide string. - * For storage it uses TagLib::wstring, but as this is an implementation detail this of course could change. + * For storage it uses std::wstring, but as this is an implementation detail this of course could change. * Strings are stored internally as UTF-16(without BOM/ CPU byte order) * * The use of implicit sharing means that copying a string is cheap, the only \e cost comes into play when the copy is modified. @@ -83,8 +83,8 @@ class StringList; class TAGLIB_EXPORT String { public: #ifndef DO_NOT_DOCUMENT - typedef Strawberry_TagLib::TagLib::wstring::iterator Iterator; - typedef Strawberry_TagLib::TagLib::wstring::const_iterator ConstIterator; + typedef std::wstring::iterator Iterator; + typedef std::wstring::const_iterator ConstIterator; #endif /** @@ -101,7 +101,7 @@ class TAGLIB_EXPORT String { */ UTF16 = 1, /*! - * UTF16 big endian. 16 bit characters. This is the encoding used internally by TagLib. + * UTF16 big endian. 16 bit characters. */ UTF16BE = 2, /*! @@ -111,7 +111,11 @@ class TAGLIB_EXPORT String { /*! * UTF16 little endian. 16 bit characters. */ - UTF16LE = 4 + UTF16LE = 4, + /*! + * UTF16 in the native byte order of the system. 16 bit characters. + */ + UTF16Native = 5 }; /*! @@ -135,19 +139,20 @@ class TAGLIB_EXPORT String { /*! * Makes a deep copy of the data in \a s. * - * /note If \a t is UTF16LE, the byte order of \a s will be swapped regardless of the CPU byte order. - * If UTF16BE, it will not be swapped. This behavior will be changed in TagLib2.0. + * \note This should only be used with the 16-bit codecs UTF16, UTF16BE or UTF16LE, + * when used with other codecs it will simply print a warning and exit. + * UTF16BE or UTF16LE is automatically chosen as default according to the CPU byte order */ - String(const wstring &s, Type t = UTF16BE); + String(const std::wstring &s, Type t = UTF16Native); /*! * Makes a deep copy of the data in \a s. * - * /note If \a t is UTF16LE, the byte order of \a s will be swapped regardless of the CPU byte order. - * If UTF16BE, it will not be swapped. - * This behavior will be changed in TagLib2.0. + * \note This should only be used with the 16-bit codecs UTF16, UTF16BE or UTF16LE, + * when used with other codecs it will simply print a warning and exit. + * UTF16BE or UTF16LE is automatically chosen as default according to the CPU byte order */ - String(const wchar_t *s, Type t = UTF16BE); + String(const wchar_t *s, Type t = UTF16Native); /*! * Makes a deep copy of the data in \a c. @@ -158,8 +163,12 @@ class TAGLIB_EXPORT String { /*! * Makes a deep copy of the data in \a c. + * + * \note This should only be used with the 16-bit codecs UTF16, UTF16BE or UTF16LE, + * when used with other codecs it will simply print a warning and exit. + * UTF16BE or UTF16LE is automatically chosen as default according to the CPU byte order */ - String(wchar_t c, Type t = Latin1); + String(wchar_t c, Type t = UTF16Native); /*! * Makes a deep copy of the data in \a s. @@ -192,7 +201,7 @@ class TAGLIB_EXPORT String { * * \see toCWString() */ - wstring toWString() const; + const std::wstring &toWString() const; /*! * Creates and returns a standard C-style (null-terminated) version of this String. @@ -246,16 +255,16 @@ class TAGLIB_EXPORT String { /*! * Finds the first occurrence of pattern \a s in this string starting from \a offset. - * If the pattern is not found, -1 is returned. + * If the pattern is not found, \a npos is returned. */ - int find(const String &s, int offset = 0) const; + size_t find(const String &s, size_t offset = 0) const; /*! * Finds the last occurrence of pattern \a s in this string, searched backwards, * either from the end of the string or starting from \a offset. - * If the pattern is not found, -1 is returned. + * If the pattern is not found, \a npos is returned. */ - int rfind(const String &s, int offset = -1) const; + size_t rfind(const String &s, size_t offset = npos()) const; /*! * Splits the string on each occurrence of \a separator. @@ -270,7 +279,7 @@ class TAGLIB_EXPORT String { /*! * Extract a substring from this string starting at \a position and continuing for \a n characters. */ - String substr(unsigned int position, unsigned int n = 0xffffffff) const; + String substr(size_t position, size_t n = npos()) const; /*! * Append \a s to the current string and return a reference to the current string. @@ -292,17 +301,15 @@ class TAGLIB_EXPORT String { /*! * Returns the size of the string. */ - unsigned int size() const; + size_t size() const; /*! * Returns the length of the string. Equivalent to size(). */ - unsigned int length() const; + size_t length() const; /*! * Returns true if the string is empty. - * - * \see isNull() */ bool isEmpty() const; @@ -347,12 +354,12 @@ class TAGLIB_EXPORT String { /*! * Returns a reference to the character at position \a i. */ - wchar_t &operator[](int i); + wchar_t &operator[](size_t i); /*! * Returns a const reference to the character at position \a i. */ - const wchar_t &operator[](int i) const; + const wchar_t &operator[](size_t i) const; /*! * Compares each character of the String with each character of \a s and returns true if the strings match. @@ -422,7 +429,7 @@ class TAGLIB_EXPORT String { /*! * Performs a deep copy of the data in \a s. */ - String &operator=(const wstring &s); + String &operator=(const std::wstring &s); /*! * Performs a deep copy of the data in \a s. @@ -460,6 +467,13 @@ class TAGLIB_EXPORT String { */ bool operator<(const String &s) const; + /*! + * Returns a special value used for \a length parameter in String's member + * functions, means "until the end of the string". + * As a return value, it is usually used to indicate no matches. + */ + static size_t npos(); + protected: /*! * If this String is being shared via implicit sharing, do a deep copy of the data and separate from the shared members. @@ -472,9 +486,6 @@ class TAGLIB_EXPORT String { StringPrivate *d; }; -} // namespace TagLib -} // namespace Strawberry_TagLib - /*! * \relates TagLib::String * @@ -504,4 +515,7 @@ TAGLIB_EXPORT const Strawberry_TagLib::TagLib::String operator+(const Strawberry */ TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::String &str); +} // namespace TagLib +} // namespace Strawberry_TagLib + #endif diff --git a/3rdparty/taglib/toolkit/tstringhandler.cpp b/3rdparty/taglib/toolkit/tstringhandler.cpp new file mode 100644 index 000000000..66a35412c --- /dev/null +++ b/3rdparty/taglib/toolkit/tstringhandler.cpp @@ -0,0 +1,30 @@ +/*************************************************************************** + copyright : (C) 2012 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 "tstringhandler.h" + +Strawberry_TagLib::TagLib::StringHandler::StringHandler() {} + +Strawberry_TagLib::TagLib::StringHandler::~StringHandler() {} diff --git a/3rdparty/taglib/toolkit/tstringhandler.h b/3rdparty/taglib/toolkit/tstringhandler.h new file mode 100644 index 000000000..a557c5746 --- /dev/null +++ b/3rdparty/taglib/toolkit/tstringhandler.h @@ -0,0 +1,72 @@ +/*************************************************************************** + copyright : (C) 2012 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_STRINGHANDLER_H +#define TAGLIB_STRINGHANDLER_H + +#include "tstring.h" +#include "tbytevector.h" +#include "taglib_export.h" + +namespace Strawberry_TagLib { +namespace TagLib { +//! A abstraction for the string to data encoding. + +/*! + * ID3v1, ID3v2 and RIFF Info tag sometimes store strings in local encodings + * encodings instead of ISO-8859-1 (Latin1), such as Windows-1252 for western + * languages, Shift_JIS for Japanese and so on. However, TagLib only supports + * genuine ISO-8859-1 by default. + * + * Here is an option to read and write tags in your preferrd encoding + * by subclassing this class, reimplementing parse() and render() and setting + * your reimplementation as the default with ID3v1::Tag::setStringHandler(), + * ID3v2::Tag::setStringHandler() or Info::Tag::setStringHandler(). + * + * \see ID3v1::Tag::setStringHandler() + * \see ID3v2::Tag::setStringHandler() + * \see Info::Tag::setStringHandler() + */ + +class TAGLIB_EXPORT StringHandler { + public: + explicit StringHandler(); + virtual ~StringHandler(); + + /*! + * Decode a string from \a data. + */ + virtual String parse(const ByteVector &data) const = 0; + + /*! + * Encode a ByteVector with the data from \a s. + */ + virtual ByteVector render(const String &s) const = 0; +}; + +} // namespace TagLib +} // namespace Strawberry_TagLib + +#endif diff --git a/3rdparty/taglib/toolkit/tstringlist.cpp b/3rdparty/taglib/toolkit/tstringlist.cpp index 9edf4b766..abe1f0024 100644 --- a/3rdparty/taglib/toolkit/tstringlist.cpp +++ b/3rdparty/taglib/toolkit/tstringlist.cpp @@ -27,9 +27,6 @@ using namespace Strawberry_TagLib::TagLib; -class StringListPrivate { -}; - //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// @@ -38,8 +35,8 @@ StringList StringList::split(const String &s, const String &pattern) { StringList l; - int previousOffset = 0; - for (int offset = s.find(pattern); offset != -1; offset = s.find(pattern, offset + 1)) { + size_t previousOffset = 0; + for (size_t offset = s.find(pattern); offset != String::npos(); offset = s.find(pattern, offset + 1)) { l.append(s.substr(previousOffset, offset - previousOffset)); previousOffset = offset + 1; } @@ -54,9 +51,11 @@ StringList StringList::split(const String &s, const String &pattern) { // public members //////////////////////////////////////////////////////////////////////////////// -StringList::StringList() : d(nullptr) {} +StringList::StringList() {} -StringList::StringList(const String &s) : d(nullptr) { +StringList::StringList(const StringList &l) : List(l) {} + +StringList::StringList(const String &s) { append(s); } @@ -69,8 +68,6 @@ StringList::StringList(const ByteVectorList &bl, String::Type t) { } -StringList::~StringList() {} - String StringList::toString(const String &separator) const { String s; @@ -103,11 +100,16 @@ StringList &StringList::append(const StringList &l) { } +StringList &StringList::operator=(const StringList &l) { + List::operator=(l); + return *this; +} + //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// -std::ostream &operator<<(std::ostream &s, const StringList &l) { +std::ostream &Strawberry_TagLib::TagLib::operator<<(std::ostream &s, const StringList &l) { s << l.toString(); return s; } diff --git a/3rdparty/taglib/toolkit/tstringlist.h b/3rdparty/taglib/toolkit/tstringlist.h index f6346c874..ea74e60c0 100644 --- a/3rdparty/taglib/toolkit/tstringlist.h +++ b/3rdparty/taglib/toolkit/tstringlist.h @@ -53,7 +53,7 @@ class TAGLIB_EXPORT StringList : public List { * Make a shallow, implicitly shared, copy of \a l. * Because this is implicitly shared, this method is lightweight and suitable for pass-by-value usage. */ - StringList(const StringList &l) = default; + StringList(const StringList &l); /*! * Constructs a StringList with \a s as a member. @@ -68,11 +68,6 @@ class TAGLIB_EXPORT StringList : public List { */ StringList(const ByteVectorList &bl, String::Type t = String::Latin1); - /*! - * Destroys this StringList instance. - */ - virtual ~StringList(); - /*! * Concatenate the list of strings into one string separated by \a separator. */ @@ -88,24 +83,26 @@ class TAGLIB_EXPORT StringList : public List { */ StringList &append(const StringList &l); + /*! + * Make a shallow, implicitly shared, copy of \a l. + * Because this is implicitly shared, this method is lightweight and suitable for pass-by-value usage. + */ + StringList &operator=(const StringList &l); + /*! * Splits the String \a s into several strings at \a pattern. * This will not include the pattern in the returned strings. */ static StringList split(const String &s, const String &pattern); - - private: - class StringListPrivate; - StringListPrivate *d; }; -} // namespace TagLib -} // namespace Strawberry_TagLib - /*! * \related Strawberry_TagLib::TagLib::StringList * Send the StringList to an output stream. */ -std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::StringList &l); +TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const Strawberry_TagLib::TagLib::StringList &l); + +} // namespace TagLib +} // namespace Strawberry_TagLib #endif diff --git a/3rdparty/taglib/toolkit/tutils.h b/3rdparty/taglib/toolkit/tutils.h index 236c9c150..19e8800ee 100644 --- a/3rdparty/taglib/toolkit/tutils.h +++ b/3rdparty/taglib/toolkit/tutils.h @@ -30,9 +30,7 @@ #ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header -# ifdef HAVE_CONFIG_H -# include -# endif +#include "taglib-config.h" # if defined(HAVE_MSC_BYTESWAP) # include @@ -175,7 +173,7 @@ inline String formatString(const char *format, ...) { // The last resort. May cause a buffer overflow. length = vsprintf(buf, format, args); - if (length >= (int)BufferSize) { + if (length >= BufferSize) { debug("Utils::formatString() - Buffer overflow! Returning an empty string."); length = -1; } @@ -190,16 +188,6 @@ inline String formatString(const char *format, ...) { return String(); } -/*! - * The types of byte order of the running system. - */ -enum ByteOrder { - //! Little endian systems. - LittleEndian, - //! Big endian systems. - BigEndian -}; - /*! * Returns the byte order of the system. */ diff --git a/3rdparty/taglib/toolkit/tzlib.cpp b/3rdparty/taglib/toolkit/tzlib.cpp index 88bebcea7..055a24f77 100644 --- a/3rdparty/taglib/toolkit/tzlib.cpp +++ b/3rdparty/taglib/toolkit/tzlib.cpp @@ -23,14 +23,12 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif +#include "taglib-config.h" #ifdef HAVE_ZLIB # include -# include -# include +# include "tstring.h" +# include "tdebug.h" #endif #include "tzlib.h" diff --git a/3rdparty/taglib/trueaudio/trueaudiofile.cpp b/3rdparty/taglib/trueaudio/trueaudiofile.cpp index 0c7989719..3b8db24dd 100644 --- a/3rdparty/taglib/trueaudio/trueaudiofile.cpp +++ b/3rdparty/taglib/trueaudio/trueaudiofile.cpp @@ -27,13 +27,13 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include +#include "tbytevector.h" +#include "tstring.h" +#include "tdebug.h" +#include "tagunion.h" +#include "tstringlist.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "trueaudiofile.h" #include "id3v1tag.h" @@ -47,7 +47,8 @@ enum { TrueAudioID3v2Index = 0, TrueAudioID3v1Index = 1 }; -} +const unsigned int HeaderSize = 18; +} // namespace class TrueAudio::File::FilePrivate { public: @@ -62,12 +63,12 @@ class TrueAudio::File::FilePrivate { } const ID3v2::FrameFactory *ID3v2FrameFactory; - long ID3v2Location; - long ID3v2OriginalSize; + long long ID3v2Location; + long long ID3v2OriginalSize; - long ID3v1Location; + long long ID3v1Location; - TagUnion tag; + DoubleTagUnion tag; AudioProperties *properties; }; @@ -125,14 +126,6 @@ Strawberry_TagLib::TagLib::Tag *TrueAudio::File::tag() const { return &d->tag; } -PropertyMap TrueAudio::File::properties() const { - return d->tag.properties(); -} - -void TrueAudio::File::removeUnsupportedProperties(const StringList &properties) { - d->tag.removeUnsupportedProperties(properties); -} - PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties) { if (ID3v1Tag()) @@ -273,7 +266,7 @@ void TrueAudio::File::read(bool readProperties) { if (readProperties) { - long streamLength; + long long streamLength; if (d->ID3v1Location >= 0) streamLength = d->ID3v1Location; @@ -288,7 +281,7 @@ void TrueAudio::File::read(bool readProperties) { seek(0); } - d->properties = new AudioProperties(readBlock(TrueAudio::HeaderSize), streamLength); + d->properties = new AudioProperties(readBlock(HeaderSize), streamLength); } } diff --git a/3rdparty/taglib/trueaudio/trueaudiofile.h b/3rdparty/taglib/trueaudio/trueaudiofile.h index df3add1bf..1239a836a 100644 --- a/3rdparty/taglib/trueaudio/trueaudiofile.h +++ b/3rdparty/taglib/trueaudio/trueaudiofile.h @@ -123,36 +123,29 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. */ - virtual Strawberry_TagLib::TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both ID3v1 and v2 tags, only ID3v2 will be converted to the PropertyMap. - */ - PropertyMap properties() const; + Strawberry_TagLib::TagLib::Tag *tag() const override; /*! * Implements the unified property interface -- import function. * Creates in ID3v2 tag if necessary. If an ID3v1 tag exists, it will be updated as well, within the limitations of ID3v1. */ - PropertyMap setProperties(const PropertyMap &); - - void removeUnsupportedProperties(const StringList &properties); + PropertyMap setProperties(const PropertyMap &) override; /*! * Returns the TrueAudio::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; + /*! * Saves the file. */ - virtual bool save(); + bool save() override; /*! * Returns a pointer to the ID3v1 tag of the file. @@ -217,7 +210,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/trueaudio/trueaudioproperties.cpp b/3rdparty/taglib/trueaudio/trueaudioproperties.cpp index 8c6aeec87..1bf082a4f 100644 --- a/3rdparty/taglib/trueaudio/trueaudioproperties.cpp +++ b/3rdparty/taglib/trueaudio/trueaudioproperties.cpp @@ -27,9 +27,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "trueaudioproperties.h" #include "trueaudiofile.h" @@ -38,13 +37,13 @@ using namespace Strawberry_TagLib::TagLib; class TrueAudio::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : version(0), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - bitsPerSample(0), - sampleFrames(0) {} + explicit AudioPropertiesPrivate() : version(0), + length(0), + bitrate(0), + sampleRate(0), + channels(0), + bitsPerSample(0), + sampleFrames(0) {} int version; int length; @@ -59,7 +58,7 @@ class TrueAudio::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -TrueAudio::AudioProperties::AudioProperties(const ByteVector &data, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +TrueAudio::AudioProperties::AudioProperties(const ByteVector &data, long long streamLength, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(data, streamLength); } @@ -103,7 +102,7 @@ int TrueAudio::AudioProperties::ttaVersion() const { // private members //////////////////////////////////////////////////////////////////////////////// -void TrueAudio::AudioProperties::read(const ByteVector &data, long streamLength) { +void TrueAudio::AudioProperties::read(const ByteVector &data, long long streamLength) { if (data.size() < 4) { debug("TrueAudio::AudioProperties::read() -- data is too short."); @@ -115,7 +114,7 @@ void TrueAudio::AudioProperties::read(const ByteVector &data, long streamLength) return; } - unsigned int pos = 3; + size_t pos = 3; d->version = data[pos] - '0'; pos += 1; @@ -131,16 +130,16 @@ void TrueAudio::AudioProperties::read(const ByteVector &data, long streamLength) // Skip the audio format pos += 2; - d->channels = data.toShort(pos, false); + d->channels = data.toUInt16LE(pos); pos += 2; - d->bitsPerSample = data.toShort(pos, false); + d->bitsPerSample = data.toUInt16LE(pos); pos += 2; - d->sampleRate = data.toUInt(pos, false); + d->sampleRate = data.toUInt32LE(pos); pos += 4; - d->sampleFrames = data.toUInt(pos, false); + d->sampleFrames = data.toUInt32LE(pos); if (d->sampleFrames > 0 && d->sampleRate > 0) { const double length = d->sampleFrames * 1000.0 / d->sampleRate; diff --git a/3rdparty/taglib/trueaudio/trueaudioproperties.h b/3rdparty/taglib/trueaudio/trueaudioproperties.h index cf0fc963c..97e573151 100644 --- a/3rdparty/taglib/trueaudio/trueaudioproperties.h +++ b/3rdparty/taglib/trueaudio/trueaudioproperties.h @@ -38,8 +38,6 @@ namespace TrueAudio { class File; -static const unsigned int HeaderSize = 18; - //! An implementation of audio property reading for TrueAudio /*! @@ -51,41 +49,41 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of TrueAudio::AudioProperties with the data read from the ByteVector \a data. */ - explicit AudioProperties(const ByteVector &data, long streamLength, ReadStyle style = Average); + explicit AudioProperties(const ByteVector &data, long long streamLength, ReadStyle style = Average); /*! * Destroys this TrueAudio::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. The length is rounded down to the nearest whole second. * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -103,10 +101,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int ttaVersion() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - - void read(const ByteVector &data, long streamLength); + void read(const ByteVector &data, long long streamLength); class AudioPropertiesPrivate; AudioPropertiesPrivate *d; diff --git a/3rdparty/taglib/wavpack/wavpackfile.cpp b/3rdparty/taglib/wavpack/wavpackfile.cpp index dacf1fd65..819078c56 100644 --- a/3rdparty/taglib/wavpack/wavpackfile.cpp +++ b/3rdparty/taglib/wavpack/wavpackfile.cpp @@ -27,12 +27,12 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include -#include -#include -#include -#include +#include "tbytevector.h" +#include "tstring.h" +#include "tdebug.h" +#include "tagunion.h" +#include "tpropertymap.h" +#include "tagutils.h" #include "wavpackfile.h" #include "id3v1tag.h" @@ -60,12 +60,12 @@ class WavPack::File::FilePrivate { delete properties; } - long APELocation; - long APESize; + long long APELocation; + long long APESize; - long ID3v1Location; + long long ID3v1Location; - TagUnion tag; + DoubleTagUnion tag; AudioProperties *properties; }; @@ -109,14 +109,6 @@ Strawberry_TagLib::TagLib::Tag *WavPack::File::tag() const { return &d->tag; } -PropertyMap WavPack::File::properties() const { - return d->tag.properties(); -} - -void WavPack::File::removeUnsupportedProperties(const StringList &properties) { - d->tag.removeUnsupportedProperties(properties); -} - PropertyMap WavPack::File::setProperties(const PropertyMap &properties) { if (ID3v1Tag()) @@ -262,7 +254,7 @@ void WavPack::File::read(bool readProperties) { if (readProperties) { - long streamLength; + long long streamLength; if (d->APELocation >= 0) streamLength = d->APELocation; diff --git a/3rdparty/taglib/wavpack/wavpackfile.h b/3rdparty/taglib/wavpack/wavpackfile.h index 2d2348cee..7cb5efaab 100644 --- a/3rdparty/taglib/wavpack/wavpackfile.h +++ b/3rdparty/taglib/wavpack/wavpackfile.h @@ -104,42 +104,33 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; /*! * Returns the Tag for this file. * This will be an APE tag, an ID3v1 tag or a combination of the two. */ - virtual Strawberry_TagLib::TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both an APE and an ID3v1 tag, - * only APE will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); + Strawberry_TagLib::TagLib::Tag *tag() const override; /*! * Implements the unified property interface -- import function. * Creates an APE tag if it does not exists and calls setProperties() on that. * Any existing ID3v1 tag will be updated as well. */ - PropertyMap setProperties(const PropertyMap &); + PropertyMap setProperties(const PropertyMap&) override; /*! * Returns the MPC::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - virtual AudioProperties *audioProperties() const; + AudioProperties *audioProperties() const override; /*! * Saves the file. * * This returns true if the save was successful. */ - virtual bool save(); + bool save() override; /*! * Returns a pointer to the ID3v1 tag of the file. @@ -205,7 +196,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File { static bool isSupported(IOStream *stream); private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/wavpack/wavpackproperties.cpp b/3rdparty/taglib/wavpack/wavpackproperties.cpp index 869d74270..c7f8634b6 100644 --- a/3rdparty/taglib/wavpack/wavpackproperties.cpp +++ b/3rdparty/taglib/wavpack/wavpackproperties.cpp @@ -27,8 +27,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include -#include +#include "tstring.h" +#include "tdebug.h" #include "wavpackproperties.h" #include "wavpackfile.h" @@ -40,14 +40,14 @@ using namespace Strawberry_TagLib::TagLib; class WavPack::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : length(0), - bitrate(0), - sampleRate(0), - channels(0), - version(0), - bitsPerSample(0), - lossless(false), - sampleFrames(0) {} + explicit AudioPropertiesPrivate() : length(0), + bitrate(0), + sampleRate(0), + channels(0), + version(0), + bitsPerSample(0), + lossless(false), + sampleFrames(0) {} int length; int bitrate; @@ -63,7 +63,7 @@ class WavPack::AudioProperties::AudioPropertiesPrivate { // public members //////////////////////////////////////////////////////////////////////////////// -WavPack::AudioProperties::AudioProperties(File *file, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) { +WavPack::AudioProperties::AudioProperties(File *file, long long streamLength, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) { read(file, streamLength); } @@ -133,7 +133,7 @@ const unsigned int sample_rates[] = { #define FINAL_BLOCK 0x1000 -void WavPack::AudioProperties::read(File *file, long streamLength) { +void WavPack::AudioProperties::read(File *file, long long streamLength) { long offset = 0; @@ -151,17 +151,17 @@ void WavPack::AudioProperties::read(File *file, long streamLength) { break; } - const unsigned int flags = data.toUInt(24, false); + const unsigned int flags = data.toUInt32LE(24); if (offset == 0) { - d->version = data.toShort(8, false); + d->version = data.toUInt16LE(8); if (d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS) break; d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - ((flags & SHIFT_MASK) >> SHIFT_LSB); d->sampleRate = sample_rates[(flags & SRATE_MASK) >> SRATE_LSB]; d->lossless = !(flags & LOSSLESS_FLAG); - d->sampleFrames = data.toUInt(12, false); + d->sampleFrames = data.toUInt32LE(12); } d->channels += (flags & MONO_FLAG) ? 1 : 2; @@ -169,7 +169,7 @@ void WavPack::AudioProperties::read(File *file, long streamLength) { if (flags & FINAL_BLOCK) break; - const unsigned int blockSize = data.toUInt(4, false); + const unsigned int blockSize = data.toUInt32LE(4); offset += blockSize + 8; } @@ -184,9 +184,9 @@ void WavPack::AudioProperties::read(File *file, long streamLength) { } -unsigned int WavPack::AudioProperties::seekFinalIndex(File *file, long streamLength) { +unsigned int WavPack::AudioProperties::seekFinalIndex(File *file, long long streamLength) { - const long offset = file->rfind("wvpk", streamLength); + const long long offset = file->rfind("wvpk", streamLength); if (offset == -1) return 0; @@ -195,16 +195,16 @@ unsigned int WavPack::AudioProperties::seekFinalIndex(File *file, long streamLen if (data.size() < 32) return 0; - const int version = data.toShort(8, false); + const int version = data.toUInt16LE(8); if (version < MIN_STREAM_VERS || version > MAX_STREAM_VERS) return 0; - const unsigned int flags = data.toUInt(24, false); + const unsigned int flags = data.toUInt32LE(24); if (!(flags & FINAL_BLOCK)) return 0; - const unsigned int blockIndex = data.toUInt(16, false); - const unsigned int blockSamples = data.toUInt(20, false); + const unsigned int blockIndex = data.toUInt32LE(16); + const unsigned int blockSamples = data.toUInt32LE(20); return blockIndex + blockSamples; diff --git a/3rdparty/taglib/wavpack/wavpackproperties.h b/3rdparty/taglib/wavpack/wavpackproperties.h index c4f51a28d..e9fe8710d 100644 --- a/3rdparty/taglib/wavpack/wavpackproperties.h +++ b/3rdparty/taglib/wavpack/wavpackproperties.h @@ -54,12 +54,12 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro /*! * Create an instance of WavPack::Properties. */ - explicit AudioProperties(File *file, long streamLength, ReadStyle style = Average); + explicit AudioProperties(File *file, long long streamLength, ReadStyle style = Average); /*! * Destroys this WavPack::AudioProperties instance. */ - virtual ~AudioProperties(); + ~AudioProperties() override; /*! * Returns the length of the file in seconds. @@ -67,29 +67,29 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro * * \see lengthInMilliseconds() */ - virtual int lengthInSeconds() const; + int lengthInSeconds() const override; /*! * Returns the length of the file in milliseconds. * * \see lengthInSeconds() */ - virtual int lengthInMilliseconds() const; + int lengthInMilliseconds() const override; /*! * Returns the average bit rate of the file in kb/s. */ - virtual int bitrate() const; + int bitrate() const override; /*! * Returns the sample rate in Hz. 0 means unknown or custom. */ - virtual int sampleRate() const; + int sampleRate() const override; /*! * Returns the number of audio channels. */ - virtual int channels() const; + int channels() const override; /*! * Returns the number of bits per audio sample. @@ -112,11 +112,8 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro int version() const; private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - - void read(File *file, long streamLength); - unsigned int seekFinalIndex(File *file, long streamLength); + void read(File *file, long long streamLength); + unsigned int seekFinalIndex(File *file, long long streamLength); class AudioPropertiesPrivate; AudioPropertiesPrivate *d; diff --git a/3rdparty/taglib/xm/xmfile.cpp b/3rdparty/taglib/xm/xmfile.cpp index 12aed28db..5d2990eb7 100644 --- a/3rdparty/taglib/xm/xmfile.cpp +++ b/3rdparty/taglib/xm/xmfile.cpp @@ -64,6 +64,8 @@ using namespace XM; * Maybe if this is useful to other formats these classes can be moved to * their own public files. */ + +namespace { class Reader { public: virtual ~Reader() { @@ -114,9 +116,9 @@ class StringReader : public ValueReader { unsigned int read(Strawberry_TagLib::TagLib::File &file, unsigned int limit) override { ByteVector data = file.readBlock(std::min(m_size, limit)); - unsigned int count = data.size(); - int index = data.find(static_cast(0)); - if (index > -1) { + size_t count = data.size(); + size_t index = data.find('\0'); + if (index != ByteVector::npos()) { data.resize(index); } data.replace('\xff', ' '); @@ -135,7 +137,7 @@ class StringReader : public ValueReader { class ByteReader : public ValueReader { public: - explicit ByteReader(unsigned char &_byte) : ValueReader(_byte) {} + explicit ByteReader(unsigned char _byte) : ValueReader(_byte) {} unsigned int read(Strawberry_TagLib::TagLib::File &file, unsigned int limit) override { ByteVector data = file.readBlock(std::min(1U, limit)); @@ -167,8 +169,13 @@ class U16Reader : public NumberReader { unsigned int read(Strawberry_TagLib::TagLib::File &file, unsigned int limit) override { ByteVector data = file.readBlock(std::min(2U, limit)); - value = data.toUShort(bigEndian); - return data.size(); + + if (bigEndian) + value = data.toUInt16BE(0); + else + value = data.toUInt16LE(0); + + return static_cast(data.size()); } unsigned int size() const override { @@ -176,15 +183,20 @@ class U16Reader : public NumberReader { } }; -class U32Reader : public NumberReader { +class U32Reader : public NumberReader { public: - U32Reader(unsigned long &_value, bool _bigEndian = true) : NumberReader(_value, _bigEndian) { + explicit U32Reader(unsigned int _value, bool _bigEndian = true) : NumberReader(_value, _bigEndian) { } unsigned int read(Strawberry_TagLib::TagLib::File &file, unsigned int limit) override { ByteVector data = file.readBlock(std::min(4U, limit)); - value = data.toUInt(bigEndian); - return data.size(); + + if (bigEndian) + value = data.toUInt32BE(0); + else + value = data.toUInt32LE(0); + + return static_cast(data.size()); } unsigned int size() const override { @@ -257,7 +269,7 @@ class StructReader : public Reader { * Read a unsigned 32 Bit integer into \a number. The byte order * is controlled by \a bigEndian. */ - StructReader &u32(unsigned long &number, bool bigEndian) { + StructReader &u32(unsigned int number, bool bigEndian) { m_readers.append(new U32Reader(number, bigEndian)); return *this; } @@ -265,14 +277,14 @@ class StructReader : public Reader { /*! * Read a unsigned 32 Bit little endian integer into \a number. */ - StructReader &u32L(unsigned long &number) { + StructReader &u32L(unsigned int number) { return u32(number, false); } /*! * Read a unsigned 32 Bit big endian integer into \a number. */ - StructReader &u32B(unsigned long &number) { + StructReader &u32B(unsigned int number) { return u32(number, true); } @@ -301,6 +313,7 @@ class StructReader : public Reader { private: List m_readers; }; +} // namespace class XM::File::FilePrivate { public: @@ -332,14 +345,6 @@ Mod::Tag *XM::File::tag() const { return &d->tag; } -PropertyMap XM::File::properties() const { - return d->tag.properties(); -} - -PropertyMap XM::File::setProperties(const PropertyMap &properties) { - return d->tag.setProperties(properties); -} - XM::AudioProperties *XM::File::audioProperties() const { return &d->properties; } @@ -358,7 +363,7 @@ bool XM::File::save() { writeString(d->tag.trackerName(), 20); seek(60); - unsigned long headerSize = 0; + unsigned int headerSize = 0; if (!readU32L(headerSize)) return false; @@ -373,7 +378,7 @@ bool XM::File::save() { // need to read patterns again in order to seek to the instruments: for (unsigned short i = 0; i < patternCount; ++i) { seek(pos); - unsigned long patternHeaderLength = 0; + unsigned int patternHeaderLength = 0; if (!readU32L(patternHeaderLength) || patternHeaderLength < 4) return false; @@ -389,12 +394,12 @@ bool XM::File::save() { unsigned int sampleNameIndex = instrumentCount; for (unsigned short i = 0; i < instrumentCount; ++i) { seek(pos); - unsigned long instrumentHeaderSize = 0; + unsigned int instrumentHeaderSize = 0; if (!readU32L(instrumentHeaderSize) || instrumentHeaderSize < 4) return false; seek(pos + 4); - const unsigned int len = std::min(22UL, instrumentHeaderSize - 4U); + const unsigned int len = std::min(22U, instrumentHeaderSize - 4U); if (i >= lines.size()) writeString(String(), len); else @@ -407,7 +412,7 @@ bool XM::File::save() { return false; } - unsigned long sampleHeaderSize = 0; + unsigned int sampleHeaderSize = 0; if (sampleCount > 0) { seek(pos + 29); if (instrumentHeaderSize < 33U || !readU32L(sampleHeaderSize)) @@ -419,13 +424,13 @@ bool XM::File::save() { for (unsigned short j = 0; j < sampleCount; ++j) { if (sampleHeaderSize > 4U) { seek(pos); - unsigned long sampleLength = 0; + unsigned int sampleLength = 0; if (!readU32L(sampleLength)) return false; if (sampleHeaderSize > 18U) { seek(pos + 18); - const unsigned int len2 = std::min(sampleHeaderSize - 18U, 22UL); + const unsigned int len2 = std::min(sampleHeaderSize - 18U, 22U); if (sampleNameIndex >= lines.size()) writeString(String(), len2); else @@ -481,7 +486,7 @@ void XM::File::read(bool) { .u16L(bpmSpeed); unsigned int count = header.read(*this, headerSize - 4U); - unsigned int size = std::min(headerSize - 4U, static_cast(header.size())); + unsigned int size = std::min(headerSize - 4U, header.size()); READ_ASSERT(count == size); @@ -508,7 +513,7 @@ void XM::File::read(bool) { pattern.byte(packingType).u16L(rowCount).u16L(dataSize); unsigned int count2 = pattern.read(*this, patternHeaderLength - 4U); - READ_ASSERT(count2 == std::min(patternHeaderLength - 4U, (unsigned long)pattern.size())); + READ_ASSERT(count2 == std::min(patternHeaderLength - 4U, pattern.size())); seek(patternHeaderLength - (4 + count2) + dataSize, Current); } @@ -531,11 +536,11 @@ void XM::File::read(bool) { // 4 for instrumentHeaderSize unsigned int count2 = 4 + instrument.read(*this, instrumentHeaderSize - 4U); - READ_ASSERT(count2 == std::min(instrumentHeaderSize, (unsigned long)instrument.size() + 4)); + READ_ASSERT(count2 == std::min(instrumentHeaderSize, instrument.size() + 4)); long offset = 0; if (sampleCount > 0) { - unsigned long sampleHeaderSize = 0; + unsigned int sampleHeaderSize = 0; sumSampleCount += sampleCount; // wouldn't know which header size to assume otherwise: READ_ASSERT(instrumentHeaderSize >= count2 + 4 && readU32L(sampleHeaderSize)); @@ -543,9 +548,9 @@ void XM::File::read(bool) { seek(instrumentHeaderSize - count2 - 4, Current); for (unsigned short j = 0; j < sampleCount; ++j) { - unsigned long sampleLength = 0; - unsigned long loopStart = 0; - unsigned long loopLength = 0; + unsigned int sampleLength = 0; + unsigned int loopStart = 0; + unsigned int loopLength = 0; unsigned char volume = 0; unsigned char finetune = 0; unsigned char sampleType = 0; @@ -566,7 +571,7 @@ void XM::File::read(bool) { .string(sampleName, 22); unsigned int count3 = sample.read(*this, sampleHeaderSize); - READ_ASSERT(count3 == std::min(sampleHeaderSize, (unsigned long)sample.size())); + READ_ASSERT(count3 == std::min(sampleHeaderSize, sample.size())); // skip unhandled header proportion: seek(sampleHeaderSize - count3, Current); diff --git a/3rdparty/taglib/xm/xmfile.h b/3rdparty/taglib/xm/xmfile.h index 3feffe9b8..c559edb7a 100644 --- a/3rdparty/taglib/xm/xmfile.h +++ b/3rdparty/taglib/xm/xmfile.h @@ -60,27 +60,15 @@ class TAGLIB_EXPORT File : public Mod::FileBase { /*! * Destroys this instance of the File. */ - virtual ~File(); + ~File() override; - Mod::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * Forwards to Mod::Tag::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Forwards to Mod::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); + Mod::Tag *tag() const override; /*! * Returns the XM::AudioProperties for this file. * If no audio properties were read then this will return a null pointer. */ - XM::AudioProperties *audioProperties() const; + XM::AudioProperties *audioProperties() const override; /*! * Save the file. @@ -88,10 +76,10 @@ class TAGLIB_EXPORT File : public Mod::FileBase { * * \note Saving Extended Module tags is not supported. */ - bool save(); + bool save() override; private: - explicit File(const File&); + File(const File&); File &operator=(const File&); void read(bool readProperties); diff --git a/3rdparty/taglib/xm/xmproperties.cpp b/3rdparty/taglib/xm/xmproperties.cpp index f0334ddd4..a364e529f 100644 --- a/3rdparty/taglib/xm/xmproperties.cpp +++ b/3rdparty/taglib/xm/xmproperties.cpp @@ -31,16 +31,16 @@ using namespace XM; class XM::AudioProperties::AudioPropertiesPrivate { public: - AudioPropertiesPrivate() : lengthInPatterns(0), - channels(0), - version(0), - restartPosition(0), - patternCount(0), - instrumentCount(0), - sampleCount(0), - flags(0), - tempo(0), - bpmSpeed(0) { + explicit AudioPropertiesPrivate() : lengthInPatterns(0), + channels(0), + version(0), + restartPosition(0), + patternCount(0), + instrumentCount(0), + sampleCount(0), + flags(0), + tempo(0), + bpmSpeed(0) { } unsigned short lengthInPatterns; @@ -55,7 +55,7 @@ class XM::AudioProperties::AudioPropertiesPrivate { unsigned short bpmSpeed; }; -XM::AudioProperties::AudioProperties(AudioProperties::ReadStyle propertiesStyle) : Strawberry_TagLib::TagLib::AudioProperties(propertiesStyle), d(new AudioPropertiesPrivate()) {} +XM::AudioProperties::AudioProperties(AudioProperties::ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) {} XM::AudioProperties::~AudioProperties() { delete d; @@ -117,6 +117,10 @@ unsigned short XM::AudioProperties::bpmSpeed() const { return d->bpmSpeed; } +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + void XM::AudioProperties::setLengthInPatterns(unsigned short lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } diff --git a/3rdparty/taglib/xm/xmproperties.h b/3rdparty/taglib/xm/xmproperties.h index 7efac2f2f..d4f33dd35 100644 --- a/3rdparty/taglib/xm/xmproperties.h +++ b/3rdparty/taglib/xm/xmproperties.h @@ -33,8 +33,10 @@ namespace Strawberry_TagLib { namespace TagLib { namespace XM { + +class File; + class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioProperties { - friend class File; public: /*! Flag bits. */ @@ -42,14 +44,14 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro LinearFreqTable = 1 // otherwise its the amiga freq. table }; - explicit AudioProperties(AudioProperties::ReadStyle propertiesStyle); - virtual ~AudioProperties(); + explicit AudioProperties(AudioProperties::ReadStyle); + ~AudioProperties() override; - int lengthInSeconds() const; - int lengthInMilliseconds() const; - int bitrate() const; - int sampleRate() const; - int channels() const; + int lengthInSeconds() const override; + int lengthInMilliseconds() const override; + int bitrate() const override; + int sampleRate() const override; + int channels() const override; unsigned short lengthInPatterns() const; unsigned short version() const; @@ -61,6 +63,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro unsigned short tempo() const; unsigned short bpmSpeed() const; + private: void setChannels(int channels); void setLengthInPatterns(unsigned short lengthInPatterns); @@ -74,9 +77,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro void setBpmSpeed(unsigned short bpmSpeed); private: - explicit AudioProperties(const AudioProperties&); - AudioProperties &operator=(const AudioProperties&); - + friend class File; class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; diff --git a/3rdparty/utf8-cpp/checked.h b/3rdparty/utf8-cpp/checked.h index 2aef5838d..e3d04ddca 100644 --- a/3rdparty/utf8-cpp/checked.h +++ b/3rdparty/utf8-cpp/checked.h @@ -41,30 +41,30 @@ namespace utf8 class invalid_code_point : public exception { uint32_t cp; public: - invalid_code_point(uint32_t codepoint) : cp(codepoint) {} - virtual const char* what() const throw() { return "Invalid code point"; } + explicit invalid_code_point(uint32_t codepoint) : cp(codepoint) {} + const char* what() const throw() override { return "Invalid code point"; } uint32_t code_point() const {return cp;} }; class invalid_utf8 : public exception { uint8_t u8; public: - invalid_utf8 (uint8_t u) : u8(u) {} - virtual const char* what() const throw() { return "Invalid UTF-8"; } + explicit invalid_utf8 (uint8_t u) : u8(u) {} + const char* what() const throw() override { return "Invalid UTF-8"; } uint8_t utf8_octet() const {return u8;} }; class invalid_utf16 : public exception { uint16_t u16; public: - invalid_utf16 (uint16_t u) : u16(u) {} - virtual const char* what() const throw() { return "Invalid UTF-16"; } + explicit invalid_utf16 (uint16_t u) : u16(u) {} + const char* what() const throw() override { return "Invalid UTF-16"; } uint16_t utf16_word() const {return u16;} }; class not_enough_room : public exception { public: - virtual const char* what() const throw() { return "Not enough space"; } + const char* what() const throw() override { return "Not enough space"; } }; /// The library API - functions intended to be called by the users diff --git a/CMakeLists.txt b/CMakeLists.txt index 75f35237e..2ef83abb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ list(APPEND COMPILE_OPTIONS -Wformat=2 -Wdisabled-optimization -Wno-sign-conversion + -Wno-bool-conversion $<$:-Woverloaded-virtual> $<$:-Wno-old-style-cast> $<$:-fpermissive> @@ -193,68 +194,21 @@ if(X11_FOUND) endif(X11_FOUND) # TAGLIB -pkg_check_modules(TAGLIB taglib) -# Only use system taglib if it's greater than 1.11.1 -# There is a bug in version 1.11.1 corrupting Ogg files, see: https://github.com/taglib/taglib/issues/864 -# If you decide to use the systems taglib, make sure it has been patched with the following commit: -# https://github.com/taglib/taglib/commit/9336c82da3a04552168f208cd7a5fa4646701ea4 -# The current taglib in 3rdparty also has the following features used by strawberry: -# - Audio file detection by content. -# - DSF and DSDIFF support -# -# Some distros create their own version numbers for taglib so versions are not reliable anymore. -# Force to use our own copy of taglib unless USE_SYSTEM_TAGLIB is set. - -option(USE_SYSTEM_TAGLIB "Use system taglib" OFF) -if (TAGLIB_FOUND AND USE_SYSTEM_TAGLIB) - if (TAGLIB_VERSION VERSION_GREATER 1.11.1) - message(STATUS "Using system taglib library") - else() - message(WARNING "Using system taglib library. Version 1.11.1 or less has a bug corrupting Ogg files, make sure your systems version has been patched!") - endif() - find_path(HAVE_TAGLIB_DSFFILE_H taglib/dsffile.h) - if(HAVE_TAGLIB_DSFFILE_H) - set(HAVE_TAGLIB_DSFFILE ON) - endif(HAVE_TAGLIB_DSFFILE_H) -else() - message(STATUS "Using builtin taglib library") - 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) - add_subdirectory(3rdparty/utf8-cpp) - add_subdirectory(3rdparty/taglib) - set(HAVE_TAGLIB_DSFFILE ON) - add_definitions(-DTAGLIB_STATIC) -endif() +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) +add_subdirectory(3rdparty/utf8-cpp) +add_subdirectory(3rdparty/taglib) +set(HAVE_TAGLIB_DSFFILE ON) +add_definitions(-DTAGLIB_STATIC) # SingleApplication -pkg_check_modules(SINGLEAPPLICATION singleapplication) -if (NOT SINGLEAPPLICATION_FOUND) - pkg_check_modules(SINGLEAPPLICATION libsingleapplication) -endif() -pkg_check_modules(SINGLECOREAPPLICATION singlecoreapplication) -if (NOT SINGLECOREAPPLICATION_FOUND) - pkg_check_modules(SINGLECOREAPPLICATION libsinglecoreapplication) -endif() -if (SINGLEAPPLICATION_FOUND AND SINGLECOREAPPLICATION_FOUND) - option(USE_SYSTEM_SINGLEAPPLICATION "Use system SingleApplication/SingleCoreApplication libraries" ON) -else(SINGLEAPPLICATION_FOUND AND SINGLECOREAPPLICATION_FOUND) - option(USE_SYSTEM_SINGLEAPPLICATION "Use system SingleApplication/SingleCoreApplication libraries" OFF) -endif(SINGLEAPPLICATION_FOUND AND SINGLECOREAPPLICATION_FOUND) -if(USE_SYSTEM_SINGLEAPPLICATION) - if (NOT SINGLEAPPLICATION_FOUND OR NOT SINGLECOREAPPLICATION_FOUND) - message(FATAL_ERROR "Missing SingleApplication or SingleCoreApplication") - endif() - message(STATUS "Using system SingleApplication and SingleCoreApplication libraries") -else(USE_SYSTEM_SINGLEAPPLICATION) - message(STATUS "Using builtin SingleApplication and SingleCoreApplication libraries") - add_subdirectory(3rdparty/singleapplication) - set(SINGLEAPPLICATION_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/singleapplication) - set(SINGLEAPPLICATION_LIBRARIES singleapplication) - set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication) - unset(SINGLEAPPLICATION_LIBRARY_DIRS) - unset(SINGLECOREAPPLICATION_LIBRARY_DIRS) -endif(USE_SYSTEM_SINGLEAPPLICATION) +add_subdirectory(3rdparty/singleapplication) +set(SINGLEAPPLICATION_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/singleapplication) +set(SINGLEAPPLICATION_LIBRARIES singleapplication) +set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication) +unset(SINGLEAPPLICATION_LIBRARY_DIRS) +unset(SINGLECOREAPPLICATION_LIBRARY_DIRS) if (APPLE) find_library(SPARKLE Sparkle) @@ -422,7 +376,6 @@ add_definitions(-DQT_NO_CAST_TO_ASCII) # Subdirectories add_subdirectory(src) add_subdirectory(dist) -add_subdirectory(tests) add_subdirectory(ext/libstrawberry-common) add_subdirectory(ext/libstrawberry-tagreader) add_subdirectory(ext/strawberry-tagreader) @@ -430,6 +383,16 @@ if(HAVE_MOODBAR) add_subdirectory(ext/gstmoodbar) endif() +option(BUILD_TESTS "Build the test suite" OFF) +option(BUILD_TAGLIB_TESTS "Build the test suite" OFF) + +if(BUILD_TESTS) + add_subdirectory(tests) +endif(BUILD_TESTS) +if(BUILD_TAGLIB_TESTS) + add_subdirectory(tests/taglib) +endif(BUILD_TAGLIB_TESTS) + # Uninstall support configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" diff --git a/cmake/FindCppUnit.cmake b/cmake/FindCppUnit.cmake new file mode 100644 index 000000000..42a92f792 --- /dev/null +++ b/cmake/FindCppUnit.cmake @@ -0,0 +1,69 @@ +# - Try to find the libcppunit libraries +# Once done this will define +# +# CppUnit_FOUND - system has libcppunit +# CPPUNIT_INCLUDE_DIR - the libcppunit include directory +# CPPUNIT_LIBRARIES - libcppunit library + +#include (MacroEnsureVersion) + +if(NOT CPPUNIT_MIN_VERSION) + SET(CPPUNIT_MIN_VERSION 1.12.0) +endif(NOT CPPUNIT_MIN_VERSION) + +FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config ) + +IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) + + # in cache already + SET(CppUnit_FOUND TRUE) + +ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) + + SET(CPPUNIT_INCLUDE_DIR) + SET(CPPUNIT_LIBRARIES) + + IF(CPPUNIT_CONFIG_EXECUTABLE) + EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_CFLAGS) + EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_LIBRARIES) + EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) + STRING(REGEX REPLACE "-I(.+)" "\\1" CPPUNIT_CFLAGS "${CPPUNIT_CFLAGS}") + ELSE(CPPUNIT_CONFIG_EXECUTABLE) + # in case win32 needs to find it the old way? + FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include ) + FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib ) + # how can we find cppunit version? + MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}") + SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION}) + ENDIF(CPPUNIT_CONFIG_EXECUTABLE) + + SET(CPPUNIT_INCLUDE_DIR ${CPPUNIT_CFLAGS} "${CPPUNIT_CFLAGS}/cppunit") + +ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) + +IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) + + SET(CppUnit_FOUND TRUE) + + if(NOT CppUnit_FIND_QUIETLY) + MESSAGE (STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}") + endif(NOT CppUnit_FIND_QUIETLY) + + IF(CPPUNIT_CONFIG_EXECUTABLE) + EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) + ENDIF(CPPUNIT_CONFIG_EXECUTABLE) + + #macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK ) + + #IF(NOT CPPUNIT_INSTALLED_VERSION_OK) + # MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required") + # SET(CppUnit_FOUND FALSE) + #ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK) + +ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) + + SET(CppUnit_FOUND FALSE CACHE BOOL "Not found cppunit library") + +ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) + +MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES) diff --git a/dist/unix/PKGBUILD.in b/dist/unix/PKGBUILD.in index 6e09ef5ba..94f028be3 100644 --- a/dist/unix/PKGBUILD.in +++ b/dist/unix/PKGBUILD.in @@ -50,10 +50,7 @@ prepare() { build() { cd build - cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DUSE_SYSTEM_TAGLIB=ON \ - -DENABLE_TRANSLATIONS=ON + cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ -DCMAKE_INSTALL_PREFIX=/usr make -j$(nproc) } diff --git a/ext/libstrawberry-tagreader/tagreader.cpp b/ext/libstrawberry-tagreader/tagreader.cpp index 490e21e87..1bf68383d 100644 --- a/ext/libstrawberry-tagreader/tagreader.cpp +++ b/ext/libstrawberry-tagreader/tagreader.cpp @@ -25,53 +25,51 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_TAGLIB_DSFFILE -# include -# include -#endif +#include "taglib/taglib.h" +#include "taglib/fileref.h" +#include "taglib/tbytevector.h" +#include "taglib/tfile.h" +#include "taglib/tlist.h" +#include "taglib/tstring.h" +#include "taglib/tstringlist.h" +#include "taglib/audioproperties.h" +#include "taglib/attachedpictureframe.h" +#include "taglib/textidentificationframe.h" +#include "taglib/unsynchronizedlyricsframe.h" +#include "taglib/xiphcomment.h" +#include "taglib/commentsframe.h" +#include "taglib/tag.h" +#include "taglib/apetag.h" +#include "taglib/apeitem.h" +#include "taglib/apeproperties.h" +#include "taglib/id3v2tag.h" +#include "taglib/id3v2frame.h" +#include "taglib/flacfile.h" +#include "taglib/oggflacfile.h" +#include "taglib/flacproperties.h" +#include "taglib/flacpicture.h" +#include "taglib/vorbisfile.h" +#include "taglib/speexfile.h" +#include "taglib/wavfile.h" +#include "taglib/wavpackfile.h" +#include "taglib/wavpackproperties.h" +#include "taglib/aifffile.h" +#include "taglib/asffile.h" +#include "taglib/asftag.h" +#include "taglib/asfattribute.h" +#include "taglib/asfproperties.h" +#include "taglib/mp4file.h" +#include "taglib/mp4tag.h" +#include "taglib/mp4item.h" +#include "taglib/mp4coverart.h" +#include "taglib/mp4properties.h" +#include "taglib/mpcfile.h" +#include "taglib/mpegfile.h" +#include "taglib/opusfile.h" +#include "taglib/trueaudiofile.h" +#include "taglib/apefile.h" +#include "taglib/dsffile.h" +#include "taglib/dsdifffile.h" #include #include @@ -119,14 +117,14 @@ TagLib::String QStringToTaglibString(const QString &s) { return TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8); } -} +} // namespace namespace { // Tags containing the year the album was originally released (in contrast to other tags that contain the release year of the current edition) const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR"; const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime"; const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear"; -} +} // namespace TagReader::TagReader() : @@ -154,10 +152,8 @@ pb::tagreader::SongMetadata_FileType TagReader::GuessFileType(TagLib::FileRef *f if (dynamic_cast(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPC; if (dynamic_cast(fileref->file())) return pb::tagreader::SongMetadata_FileType_TRUEAUDIO; if (dynamic_cast(fileref->file())) return pb::tagreader::SongMetadata_FileType_APE; -#ifdef HAVE_TAGLIB_DSFFILE if (dynamic_cast(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSF; if (dynamic_cast(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSDIFF; -#endif return pb::tagreader::SongMetadata_FileType_UNKNOWN; @@ -472,7 +468,7 @@ void TagReader::ParseAPETag(const TagLib::APE::ItemListMap &map, const QTextCode TagLib::APE::ItemListMap::ConstIterator it = map.find("ALBUM ARTIST"); if (it != map.end()) { - TagLib::StringList album_artists = it->second.toStringList(); + TagLib::StringList album_artists = it->second.values(); if (!album_artists.isEmpty()) { Decode(album_artists.front(), nullptr, song->mutable_albumartist()); } @@ -488,15 +484,15 @@ void TagReader::ParseAPETag(const TagLib::APE::ItemListMap &map, const QTextCode } if (map.contains("PERFORMER")) { - Decode(map["PERFORMER"].toStringList().toString(", "), nullptr, song->mutable_performer()); + Decode(map["PERFORMER"].values().toString(", "), nullptr, song->mutable_performer()); } if (map.contains("COMPOSER")) { - Decode(map["COMPOSER"].toStringList().toString(", "), nullptr, song->mutable_composer()); + Decode(map["COMPOSER"].values().toString(", "), nullptr, song->mutable_composer()); } if (map.contains("GROUPING")) { - Decode(map["GROUPING"].toStringList().toString(" "), nullptr, song->mutable_grouping()); + Decode(map["GROUPING"].values().toString(" "), nullptr, song->mutable_grouping()); } if (map.contains("LYRICS")) { diff --git a/ext/libstrawberry-tagreader/tagreader.h b/ext/libstrawberry-tagreader/tagreader.h index 5838c3a53..78ad4b669 100644 --- a/ext/libstrawberry-tagreader/tagreader.h +++ b/ext/libstrawberry-tagreader/tagreader.h @@ -37,9 +37,7 @@ class QTextCodec; -#ifndef USE_SYSTEM_TAGLIB using namespace Strawberry_TagLib; -#endif class FileRefFactory; @@ -49,7 +47,7 @@ class FileRefFactory; */ class TagReader { public: - TagReader(); + explicit TagReader(); ~TagReader(); pb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const; @@ -79,7 +77,6 @@ class TagReader { void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const; private: - FileRefFactory *factory_; const std::string kEmbeddedCover; diff --git a/src/config.h.in b/src/config.h.in index 4e80b1094..2ee3b2dae 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -55,7 +55,6 @@ #cmakedefine HAVE_KEYSYMDEF_H #cmakedefine HAVE_XF86KEYSYM_H -#cmakedefine USE_SYSTEM_TAGLIB #cmakedefine USE_BUNDLE #define USE_BUNDLE_DIR "${USE_BUNDLE_DIR}" diff --git a/src/core/song.cpp b/src/core/song.cpp index a09675f17..321e08b36 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -68,9 +68,7 @@ #include "covermanager/albumcoverloader.h" #include "tagreadermessages.pb.h" -#ifndef USE_SYSTEM_TAGLIB using namespace Strawberry_TagLib; -#endif const QStringList Song::kColumns = QStringList() << "title" << "album" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f5105fe35..bcf28bdc2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,93 +1,99 @@ -find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Test) -find_package(GTest) -find_library(GMOCK_LIBRARY gmock) +enable_testing() -if(Qt5Test_FOUND AND GTEST_FOUND AND GMOCK_LIBRARY) +find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Test REQUIRED) +find_package(GTest REQUIRED) +find_library(GMOCK_LIBRARY gmock REQUIRED) - include_directories(${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS} ${QT_QTTEST_INCLUDE_DIR}) - include_directories(${TAGLIB_INCLUDE_DIRS}) - if(HAVE_GSTREAMER) - link_directories(${GSTREAMER_LIBRARY_DIRS}) - include_directories(${GSTREAMER_INCLUDE_DIRS}) - include_directories(${GSTREAMER_APP_INCLUDE_DIRS}) - include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS}) - include_directories(${GSTREAMER_BASE_INCLUDE_DIRS}) - include_directories(${GSTREAMER_TAG_INCLUDE_DIRS}) - endif() - include_directories(${CMAKE_SOURCE_DIR}/src) - include_directories(${CMAKE_BINARY_DIR}/src) - include_directories(${CMAKE_SOURCE_DIR}/tests/src) - include_directories(${CMAKE_BINARY_DIR}/tests/src) - include_directories(${CMAKE_SOURCE_DIR}/ext/strawberry-tagreader) - include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-common) - include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader) - include_directories(${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader) - if(HAVE_LIBGPOD) - include_directories(${LIBGPOD_INCLUDE_DIRS}) - endif(HAVE_LIBGPOD) +add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1) - add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1) +set(TESTUTILS-SOURCES + src/mock_networkaccessmanager.cpp + src/mock_playlistitem.cpp + src/test_utils.cpp + src/testobjectdecorators.cpp +) - set(TESTUTILS-SOURCES - src/mock_networkaccessmanager.cpp - src/mock_playlistitem.cpp - src/test_utils.cpp - src/testobjectdecorators.cpp +set(TESTUTILS-MOC-HEADERS src/mock_networkaccessmanager.h src/test_utils.h src/testobjectdecorators.h) + +qt5_wrap_cpp(TESTUTILS-SOURCES-MOC ${TESTUTILS-MOC-HEADERS}) + +add_library(test_utils STATIC EXCLUDE_FROM_ALL ${TESTUTILS-SOURCES} ${TESTUTILS-SOURCES-MOC}) +target_include_directories(test_utils SYSTEM PRIVATE + ${GTEST_INCLUDE_DIRS} + ${GMOCK_INCLUDE_DIRS} + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Widgets_INCLUDE_DIRS} + ${Qt5Network_INCLUDE_DIRS} + ${Qt5Sql_INCLUDE_DIRS} + ${Qt5Test_INCLUDE_DIRS} +) +target_include_directories(test_utils PRIVATE + ${CMAKE_BINARY_DIR}/src + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common +) +target_link_libraries(test_utils PRIVATE + ${GTEST_BOTH_LIBRARIES} + ${GMOCK_LIBRARY} + ${Qt5Core_LIBRARIES} + ${Qt5Test_LIBRARIES} +) +if(HAVE_GSTREAMER) + target_include_directories(test_utils SYSTEM PRIVATE + ${GSTREAMER_INCLUDE_DIRS} + ${GSTREAMER_BASE_INCLUDE_DIRS} + ${GSTREAMER_APP_INCLUDE_DIRS} + ${GSTREAMER_AUDIO_INCLUDE_DIRS} + ${GSTREAMER_TAG_INCLUDE_DIRS} ) +endif(HAVE_GSTREAMER) - set(TESTUTILS-MOC-HEADERS src/mock_networkaccessmanager.h src/test_utils.h src/testobjectdecorators.h) +add_custom_target(strawberry_tests echo "Running Strawberry tests" WORKING_DIRECTORY ${CURRENT_BINARY_DIR}) +add_custom_target(build_tests WORKING_DIRECTORY ${CURRENT_BINARY_DIR}) +add_dependencies(strawberry_tests build_tests) - qt5_wrap_cpp(TESTUTILS-SOURCES-MOC ${TESTUTILS-MOC-HEADERS}) +qt5_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc) - add_library(test_utils STATIC EXCLUDE_FROM_ALL ${TESTUTILS-SOURCES} ${TESTUTILS-SOURCES-MOC}) - target_link_libraries(test_utils ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${QT_LIBRARIES} ${Qt5Test_LIBRARIES}) +add_library(test_gui_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp) +if(HAVE_GSTREAMER) + target_include_directories(test_gui_main SYSTEM PRIVATE ${GSTREAMER_INCLUDE_DIRS}) +endif(HAVE_GSTREAMER) +target_link_libraries(test_gui_main strawberry_lib) +set_target_properties(test_gui_main PROPERTIES COMPILE_DEFINITIONS GUI) - add_custom_target(strawberry_test echo "Running Strawberry tests" WORKING_DIRECTORY ${CURRENT_BINARY_DIR}) - add_custom_target(build_tests WORKING_DIRECTORY ${CURRENT_BINARY_DIR}) - add_dependencies(strawberry_test build_tests) +add_library(test_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp) +if(HAVE_GSTREAMER) + target_include_directories(test_main SYSTEM PRIVATE ${GSTREAMER_INCLUDE_DIRS}) +endif(HAVE_GSTREAMER) +target_link_libraries(test_main PRIVATE strawberry_lib) - qt5_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc) +# Given a file foo_test.cpp, creates a target foo_test and adds it to the test target. +macro(add_test_file test_source gui_required) + get_filename_component(TEST_NAME ${test_source} NAME_WE) + add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${test_source}) + target_include_directories(${TEST_NAME} SYSTEM PRIVATE ${GTEST_INCLUDE_DIRS} ${Qt5Test_INCLUDE_DIRS}) + target_link_libraries(${TEST_NAME} PRIVATE strawberry_lib test_utils) + set(GUI_REQUIRED ${gui_required}) + if(GUI_REQUIRED) + target_link_libraries(${TEST_NAME} PRIVATE test_gui_main) + else(GUI_REQUIRED) + target_link_libraries(${TEST_NAME} PRIVATE test_main) + endif(GUI_REQUIRED) - add_library(test_gui_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp) - target_link_libraries(test_gui_main strawberry_lib) - set_target_properties(test_gui_main PROPERTIES COMPILE_DEFINITIONS GUI) + add_test(strawberry_tests ${TEST_NAME}) + add_custom_command(TARGET strawberry_tests POST_BUILD COMMAND ./${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX}) + add_dependencies(build_tests ${TEST_NAME}) +endmacro(add_test_file) - add_library(test_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp) - target_link_libraries(test_main strawberry_lib) +add_test_file(src/utilities_test.cpp false) +add_test_file(src/concurrentrun_test.cpp false) +add_test_file(src/closure_test.cpp false) +add_test_file(src/mergedproxymodel_test.cpp false) +add_test_file(src/sqlite_test.cpp false) +add_test_file(src/song_test.cpp false) +add_test_file(src/collectionbackend_test.cpp false) +add_test_file(src/collectionmodel_test.cpp true) +add_test_file(src/songplaylistitem_test.cpp false) +add_test_file(src/organiseformat_test.cpp false) - # Given a file foo_test.cpp, creates a target foo_test and adds it to the test target. - macro(add_test_file test_source gui_required) - get_filename_component(TEST_NAME ${test_source} NAME_WE) - add_executable(${TEST_NAME} - EXCLUDE_FROM_ALL - ${test_source} - ) - target_link_libraries(${TEST_NAME} ${GMOCK_LIBRARY} strawberry_lib test_utils Qt5::Test) - set(GUI_REQUIRED ${gui_required}) - if (GUI_REQUIRED) - target_link_libraries(${TEST_NAME} test_gui_main) - else (GUI_REQUIRED) - target_link_libraries(${TEST_NAME} test_main) - endif (GUI_REQUIRED) - - check_cxx_compiler_flag("-Wno-bool-conversions" SUPPORTS_NOBOOL) - if (SUPPORTS_NOBOOL) - set_target_properties(${TEST_NAME} PROPERTIES COMPILE_FLAGS "-Wno-bool-conversions") - endif (SUPPORTS_NOBOOL) - - add_custom_command(TARGET strawberry_test POST_BUILD COMMAND ./${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX}) - add_dependencies(build_tests ${TEST_NAME}) - endmacro (add_test_file) - - add_test_file(src/utilities_test.cpp false) - add_test_file(src/concurrentrun_test.cpp false) - add_test_file(src/closure_test.cpp false) - add_test_file(src/mergedproxymodel_test.cpp false) - add_test_file(src/sqlite_test.cpp false) - add_test_file(src/song_test.cpp false) - add_test_file(src/collectionbackend_test.cpp false) - add_test_file(src/collectionmodel_test.cpp true) - add_test_file(src/songplaylistitem_test.cpp false) - add_test_file(src/organiseformat_test.cpp false) - -endif() # Qt5Test_FOUND AND GTEST_FOUND AND GMOCK_LIBRARY +add_custom_target(run_strawberry_tests COMMAND ${CMAKE_CTEST_COMMAND} -V DEPENDS strawberry_tests) diff --git a/tests/taglib/CMakeLists.txt b/tests/taglib/CMakeLists.txt new file mode 100644 index 000000000..68b602b45 --- /dev/null +++ b/tests/taglib/CMakeLists.txt @@ -0,0 +1,91 @@ +enable_testing() +find_package(CppUnit REQUIRED) + +SET(TAGLIB_TESTS_SOURCES + main.cpp + test_list.cpp + test_map.cpp + test_mpeg.cpp + test_synchdata.cpp + test_trueaudio.cpp + test_bytevector.cpp + test_bytevectorlist.cpp + test_bytevectorstream.cpp + test_string.cpp + test_propertymap.cpp + test_file.cpp + test_fileref.cpp + test_id3v1.cpp + test_id3v2.cpp + test_xiphcomment.cpp + test_aiff.cpp + test_riff.cpp + test_ogg.cpp + test_oggflac.cpp + test_flac.cpp + test_flacpicture.cpp + test_flacunknownmetadatablock.cpp + test_ape.cpp + test_apetag.cpp + test_wav.cpp + test_info.cpp + test_wavpack.cpp + test_mp4.cpp + test_mp4item.cpp + test_mp4coverart.cpp + test_asf.cpp + test_mod.cpp + test_s3m.cpp + test_it.cpp + test_xm.cpp + test_mpc.cpp + test_opus.cpp + test_speex.cpp + test_dsf.cpp + test_dsdiff.cpp +) + +link_directories(${TAGLIB_LIBRARY_DIRS}) + +add_executable(taglib_tests ${TAGLIB_TESTS_SOURCES}) + +target_include_directories(taglib_tests PRIVATE + ${CPPUNIT_INCLUDE_DIR} + ${TAGLIB_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR}/../../3rdparty/taglib + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/toolkit + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/ape + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/asf + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mpeg/id3v1 + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mpeg/id3v2 + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mpeg/id3v2/frames + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mpeg + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mpc + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mp4 + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/riff + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/riff/aiff + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/riff/wav + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/trueaudio + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/ogg + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/ogg/vorbis + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/ogg/flac + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/ogg/speex + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/ogg/opus + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/flac + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/wavpack + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/mod + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/s3m + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/it + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/xm + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/dsf + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/taglib/dsdiff +) + +target_link_libraries(taglib_tests PRIVATE + ${CPPUNIT_LIBRARIES} + ${TAGLIB_LIBRARIES} +) + +add_test(taglib_tests taglib_tests) +add_custom_target(run_taglib_tests COMMAND ${CMAKE_CTEST_COMMAND} -V DEPENDS taglib_tests) diff --git a/tests/taglib/data/005411.id3 b/tests/taglib/data/005411.id3 new file mode 100644 index 000000000..ab2e0997a Binary files /dev/null and b/tests/taglib/data/005411.id3 differ diff --git a/tests/taglib/data/64bit.mp4 b/tests/taglib/data/64bit.mp4 new file mode 100644 index 000000000..0bd7f9f33 Binary files /dev/null and b/tests/taglib/data/64bit.mp4 differ diff --git a/tests/taglib/data/alaw.aifc b/tests/taglib/data/alaw.aifc new file mode 100644 index 000000000..33b4ea2a5 Binary files /dev/null and b/tests/taglib/data/alaw.aifc differ diff --git a/tests/taglib/data/alaw.wav b/tests/taglib/data/alaw.wav new file mode 100644 index 000000000..cf548effc Binary files /dev/null and b/tests/taglib/data/alaw.wav differ diff --git a/tests/taglib/data/ape-id3v1.mp3 b/tests/taglib/data/ape-id3v1.mp3 new file mode 100644 index 000000000..a761d6ca6 Binary files /dev/null and b/tests/taglib/data/ape-id3v1.mp3 differ diff --git a/tests/taglib/data/ape-id3v2.mp3 b/tests/taglib/data/ape-id3v2.mp3 new file mode 100644 index 000000000..72c1291d1 Binary files /dev/null and b/tests/taglib/data/ape-id3v2.mp3 differ diff --git a/tests/taglib/data/ape.mp3 b/tests/taglib/data/ape.mp3 new file mode 100644 index 000000000..a17e26993 Binary files /dev/null and b/tests/taglib/data/ape.mp3 differ diff --git a/tests/taglib/data/bladeenc.mp3 b/tests/taglib/data/bladeenc.mp3 new file mode 100644 index 000000000..e3d1a4b51 Binary files /dev/null and b/tests/taglib/data/bladeenc.mp3 differ diff --git a/tests/taglib/data/blank_video.m4v b/tests/taglib/data/blank_video.m4v new file mode 100644 index 000000000..4bb15ded3 Binary files /dev/null and b/tests/taglib/data/blank_video.m4v differ diff --git a/tests/taglib/data/broken-tenc.id3 b/tests/taglib/data/broken-tenc.id3 new file mode 100644 index 000000000..809040506 Binary files /dev/null and b/tests/taglib/data/broken-tenc.id3 differ diff --git a/tests/taglib/data/changed.s3m b/tests/taglib/data/changed.s3m new file mode 100644 index 000000000..37bd49cdd Binary files /dev/null and b/tests/taglib/data/changed.s3m differ diff --git a/tests/taglib/data/changed.xm b/tests/taglib/data/changed.xm new file mode 100644 index 000000000..bb5db3ddd Binary files /dev/null and b/tests/taglib/data/changed.xm differ diff --git a/tests/taglib/data/click.mpc b/tests/taglib/data/click.mpc new file mode 100644 index 000000000..a41f14e9e Binary files /dev/null and b/tests/taglib/data/click.mpc differ diff --git a/tests/taglib/data/click.wv b/tests/taglib/data/click.wv new file mode 100644 index 000000000..f8bd1a851 Binary files /dev/null and b/tests/taglib/data/click.wv differ diff --git a/tests/taglib/data/compressed_id3_frame.mp3 b/tests/taglib/data/compressed_id3_frame.mp3 new file mode 100644 index 000000000..824d036fa Binary files /dev/null and b/tests/taglib/data/compressed_id3_frame.mp3 differ diff --git a/tests/taglib/data/correctness_gain_silent_output.opus b/tests/taglib/data/correctness_gain_silent_output.opus new file mode 100644 index 000000000..00972c42f Binary files /dev/null and b/tests/taglib/data/correctness_gain_silent_output.opus differ diff --git a/tests/taglib/data/covr-junk.m4a b/tests/taglib/data/covr-junk.m4a new file mode 100644 index 000000000..ac80cb29d Binary files /dev/null and b/tests/taglib/data/covr-junk.m4a differ diff --git a/tests/taglib/data/duplicate_id3v2.aiff b/tests/taglib/data/duplicate_id3v2.aiff new file mode 100644 index 000000000..6703583f2 Binary files /dev/null and b/tests/taglib/data/duplicate_id3v2.aiff differ diff --git a/tests/taglib/data/duplicate_id3v2.mp3 b/tests/taglib/data/duplicate_id3v2.mp3 new file mode 100644 index 000000000..34f4f158c Binary files /dev/null and b/tests/taglib/data/duplicate_id3v2.mp3 differ diff --git a/tests/taglib/data/duplicate_tags.wav b/tests/taglib/data/duplicate_tags.wav new file mode 100644 index 000000000..b9865bbd5 Binary files /dev/null and b/tests/taglib/data/duplicate_tags.wav differ diff --git a/tests/taglib/data/empty-seektable.flac b/tests/taglib/data/empty-seektable.flac new file mode 100644 index 000000000..20dd90d91 Binary files /dev/null and b/tests/taglib/data/empty-seektable.flac differ diff --git a/tests/taglib/data/empty.aiff b/tests/taglib/data/empty.aiff new file mode 100644 index 000000000..849b762da Binary files /dev/null and b/tests/taglib/data/empty.aiff differ diff --git a/tests/taglib/data/empty.dsf b/tests/taglib/data/empty.dsf new file mode 100644 index 000000000..373a73b46 Binary files /dev/null and b/tests/taglib/data/empty.dsf differ diff --git a/tests/taglib/data/empty.ogg b/tests/taglib/data/empty.ogg new file mode 100644 index 000000000..aa533104d Binary files /dev/null and b/tests/taglib/data/empty.ogg differ diff --git a/tests/taglib/data/empty.spx b/tests/taglib/data/empty.spx new file mode 100644 index 000000000..70572b458 Binary files /dev/null and b/tests/taglib/data/empty.spx differ diff --git a/tests/taglib/data/empty.tta b/tests/taglib/data/empty.tta new file mode 100644 index 000000000..9cc00ba81 Binary files /dev/null and b/tests/taglib/data/empty.tta differ diff --git a/tests/taglib/data/empty.wav b/tests/taglib/data/empty.wav new file mode 100644 index 000000000..74b5a6de7 Binary files /dev/null and b/tests/taglib/data/empty.wav differ diff --git a/tests/taglib/data/empty10ms.dff b/tests/taglib/data/empty10ms.dff new file mode 100644 index 000000000..9dc0b9ecd Binary files /dev/null and b/tests/taglib/data/empty10ms.dff differ diff --git a/tests/taglib/data/empty10ms.dsf b/tests/taglib/data/empty10ms.dsf new file mode 100644 index 000000000..31a4d7c1b Binary files /dev/null and b/tests/taglib/data/empty10ms.dsf differ diff --git a/tests/taglib/data/empty_alac.m4a b/tests/taglib/data/empty_alac.m4a new file mode 100644 index 000000000..8c6783218 Binary files /dev/null and b/tests/taglib/data/empty_alac.m4a differ diff --git a/tests/taglib/data/empty_flac.oga b/tests/taglib/data/empty_flac.oga new file mode 100644 index 000000000..444587fd0 Binary files /dev/null and b/tests/taglib/data/empty_flac.oga differ diff --git a/tests/taglib/data/empty_vorbis.oga b/tests/taglib/data/empty_vorbis.oga new file mode 100644 index 000000000..aa533104d Binary files /dev/null and b/tests/taglib/data/empty_vorbis.oga differ diff --git a/tests/taglib/data/excessive_alloc.aif b/tests/taglib/data/excessive_alloc.aif new file mode 100644 index 000000000..9cb3a6e10 Binary files /dev/null and b/tests/taglib/data/excessive_alloc.aif differ diff --git a/tests/taglib/data/excessive_alloc.mp3 b/tests/taglib/data/excessive_alloc.mp3 new file mode 100644 index 000000000..cd8aa2aba Binary files /dev/null and b/tests/taglib/data/excessive_alloc.mp3 differ diff --git a/tests/taglib/data/float64.wav b/tests/taglib/data/float64.wav new file mode 100644 index 000000000..d34f692bf Binary files /dev/null and b/tests/taglib/data/float64.wav differ diff --git a/tests/taglib/data/four_channels.wv b/tests/taglib/data/four_channels.wv new file mode 100644 index 000000000..de682f242 Binary files /dev/null and b/tests/taglib/data/four_channels.wv differ diff --git a/tests/taglib/data/garbage.mp3 b/tests/taglib/data/garbage.mp3 new file mode 100644 index 000000000..730b74e7c Binary files /dev/null and b/tests/taglib/data/garbage.mp3 differ diff --git a/tests/taglib/data/gnre.m4a b/tests/taglib/data/gnre.m4a new file mode 100644 index 000000000..f925ea9eb Binary files /dev/null and b/tests/taglib/data/gnre.m4a differ diff --git a/tests/taglib/data/has-tags.m4a b/tests/taglib/data/has-tags.m4a new file mode 100644 index 000000000..f48a28b52 Binary files /dev/null and b/tests/taglib/data/has-tags.m4a differ diff --git a/tests/taglib/data/id3v22-tda.mp3 b/tests/taglib/data/id3v22-tda.mp3 new file mode 100644 index 000000000..b0545ea6f Binary files /dev/null and b/tests/taglib/data/id3v22-tda.mp3 differ diff --git a/tests/taglib/data/ilst-is-last.m4a b/tests/taglib/data/ilst-is-last.m4a new file mode 100644 index 000000000..c56c80498 Binary files /dev/null and b/tests/taglib/data/ilst-is-last.m4a differ diff --git a/tests/taglib/data/infloop.m4a b/tests/taglib/data/infloop.m4a new file mode 100644 index 000000000..bbf76db8f Binary files /dev/null and b/tests/taglib/data/infloop.m4a differ diff --git a/tests/taglib/data/infloop.mpc b/tests/taglib/data/infloop.mpc new file mode 100644 index 000000000..46861ab37 Binary files /dev/null and b/tests/taglib/data/infloop.mpc differ diff --git a/tests/taglib/data/infloop.wav b/tests/taglib/data/infloop.wav new file mode 100644 index 000000000..c220baa8f Binary files /dev/null and b/tests/taglib/data/infloop.wav differ diff --git a/tests/taglib/data/infloop.wv b/tests/taglib/data/infloop.wv new file mode 100644 index 000000000..d8c720cfe Binary files /dev/null and b/tests/taglib/data/infloop.wv differ diff --git a/tests/taglib/data/invalid-frames1.mp3 b/tests/taglib/data/invalid-frames1.mp3 new file mode 100644 index 000000000..c076712c0 Binary files /dev/null and b/tests/taglib/data/invalid-frames1.mp3 differ diff --git a/tests/taglib/data/invalid-frames2.mp3 b/tests/taglib/data/invalid-frames2.mp3 new file mode 100644 index 000000000..01976fc54 Binary files /dev/null and b/tests/taglib/data/invalid-frames2.mp3 differ diff --git a/tests/taglib/data/invalid-frames3.mp3 b/tests/taglib/data/invalid-frames3.mp3 new file mode 100644 index 000000000..6bbd2d397 Binary files /dev/null and b/tests/taglib/data/invalid-frames3.mp3 differ diff --git a/tests/taglib/data/lame_cbr.mp3 b/tests/taglib/data/lame_cbr.mp3 new file mode 100644 index 000000000..b7badeb05 Binary files /dev/null and b/tests/taglib/data/lame_cbr.mp3 differ diff --git a/tests/taglib/data/lame_vbr.mp3 b/tests/taglib/data/lame_vbr.mp3 new file mode 100644 index 000000000..643056ef8 Binary files /dev/null and b/tests/taglib/data/lame_vbr.mp3 differ diff --git a/tests/taglib/data/longloop.ape b/tests/taglib/data/longloop.ape new file mode 100644 index 000000000..3800387ac Binary files /dev/null and b/tests/taglib/data/longloop.ape differ diff --git a/tests/taglib/data/lossless.wma b/tests/taglib/data/lossless.wma new file mode 100644 index 000000000..e29befcc8 Binary files /dev/null and b/tests/taglib/data/lossless.wma differ diff --git a/tests/taglib/data/lowercase-fields.ogg b/tests/taglib/data/lowercase-fields.ogg new file mode 100644 index 000000000..0ddd49357 Binary files /dev/null and b/tests/taglib/data/lowercase-fields.ogg differ diff --git a/tests/taglib/data/mac-390-hdr.ape b/tests/taglib/data/mac-390-hdr.ape new file mode 100644 index 000000000..c703e2e2f Binary files /dev/null and b/tests/taglib/data/mac-390-hdr.ape differ diff --git a/tests/taglib/data/mac-396.ape b/tests/taglib/data/mac-396.ape new file mode 100644 index 000000000..fa7ae4149 Binary files /dev/null and b/tests/taglib/data/mac-396.ape differ diff --git a/tests/taglib/data/mac-399-id3v2.ape b/tests/taglib/data/mac-399-id3v2.ape new file mode 100644 index 000000000..2ea97fc45 Binary files /dev/null and b/tests/taglib/data/mac-399-id3v2.ape differ diff --git a/tests/taglib/data/mac-399-tagged.ape b/tests/taglib/data/mac-399-tagged.ape new file mode 100644 index 000000000..3f5a656eb Binary files /dev/null and b/tests/taglib/data/mac-399-tagged.ape differ diff --git a/tests/taglib/data/mac-399.ape b/tests/taglib/data/mac-399.ape new file mode 100644 index 000000000..3b0661ee1 Binary files /dev/null and b/tests/taglib/data/mac-399.ape differ diff --git a/tests/taglib/data/matroska.mka b/tests/taglib/data/matroska.mka new file mode 100644 index 000000000..e85bd338b Binary files /dev/null and b/tests/taglib/data/matroska.mka differ diff --git a/tests/taglib/data/mpeg2.mp3 b/tests/taglib/data/mpeg2.mp3 new file mode 100644 index 000000000..13e8d53df Binary files /dev/null and b/tests/taglib/data/mpeg2.mp3 differ diff --git a/tests/taglib/data/multiple-vc.flac b/tests/taglib/data/multiple-vc.flac new file mode 100644 index 000000000..93d9a8a14 Binary files /dev/null and b/tests/taglib/data/multiple-vc.flac differ diff --git a/tests/taglib/data/no-extension b/tests/taglib/data/no-extension new file mode 100644 index 000000000..65f57c2ee Binary files /dev/null and b/tests/taglib/data/no-extension differ diff --git a/tests/taglib/data/no-tags.3g2 b/tests/taglib/data/no-tags.3g2 new file mode 100644 index 000000000..d31a6ce96 Binary files /dev/null and b/tests/taglib/data/no-tags.3g2 differ diff --git a/tests/taglib/data/no-tags.flac b/tests/taglib/data/no-tags.flac new file mode 100644 index 000000000..417144167 Binary files /dev/null and b/tests/taglib/data/no-tags.flac differ diff --git a/tests/taglib/data/no-tags.m4a b/tests/taglib/data/no-tags.m4a new file mode 100644 index 000000000..ba4e92bae Binary files /dev/null and b/tests/taglib/data/no-tags.m4a differ diff --git a/tests/taglib/data/no_length.wv b/tests/taglib/data/no_length.wv new file mode 100644 index 000000000..c06d1071d Binary files /dev/null and b/tests/taglib/data/no_length.wv differ diff --git a/tests/taglib/data/noise.aif b/tests/taglib/data/noise.aif new file mode 100644 index 000000000..310b995e3 Binary files /dev/null and b/tests/taglib/data/noise.aif differ diff --git a/tests/taglib/data/noise_odd.aif b/tests/taglib/data/noise_odd.aif new file mode 100644 index 000000000..bccfd7283 Binary files /dev/null and b/tests/taglib/data/noise_odd.aif differ diff --git a/tests/taglib/data/pcm_with_fact_chunk.wav b/tests/taglib/data/pcm_with_fact_chunk.wav new file mode 100644 index 000000000..a6dc1d6c5 Binary files /dev/null and b/tests/taglib/data/pcm_with_fact_chunk.wav differ diff --git a/tests/taglib/data/rare_frames.mp3 b/tests/taglib/data/rare_frames.mp3 new file mode 100644 index 000000000..e485337f9 Binary files /dev/null and b/tests/taglib/data/rare_frames.mp3 differ diff --git a/tests/taglib/data/segfault.aif b/tests/taglib/data/segfault.aif new file mode 100644 index 000000000..5dce192b0 Binary files /dev/null and b/tests/taglib/data/segfault.aif differ diff --git a/tests/taglib/data/segfault.mpc b/tests/taglib/data/segfault.mpc new file mode 100644 index 000000000..2c7e29fb7 Binary files /dev/null and b/tests/taglib/data/segfault.mpc differ diff --git a/tests/taglib/data/segfault.oga b/tests/taglib/data/segfault.oga new file mode 100644 index 000000000..e23c21706 Binary files /dev/null and b/tests/taglib/data/segfault.oga differ diff --git a/tests/taglib/data/segfault.wav b/tests/taglib/data/segfault.wav new file mode 100644 index 000000000..0385e99be Binary files /dev/null and b/tests/taglib/data/segfault.wav differ diff --git a/tests/taglib/data/segfault2.mpc b/tests/taglib/data/segfault2.mpc new file mode 100644 index 000000000..fcfa982f6 --- /dev/null +++ b/tests/taglib/data/segfault2.mpc @@ -0,0 +1 @@ +MPCKSH \ No newline at end of file diff --git a/tests/taglib/data/silence-1.wma b/tests/taglib/data/silence-1.wma new file mode 100644 index 000000000..e06f91766 Binary files /dev/null and b/tests/taglib/data/silence-1.wma differ diff --git a/tests/taglib/data/silence-44-s.flac b/tests/taglib/data/silence-44-s.flac new file mode 100644 index 000000000..24e15deb8 Binary files /dev/null and b/tests/taglib/data/silence-44-s.flac differ diff --git a/tests/taglib/data/sinewave.flac b/tests/taglib/data/sinewave.flac new file mode 100644 index 000000000..25d31b2d7 Binary files /dev/null and b/tests/taglib/data/sinewave.flac differ diff --git a/tests/taglib/data/stripped.xm b/tests/taglib/data/stripped.xm new file mode 100644 index 000000000..57055f5f1 Binary files /dev/null and b/tests/taglib/data/stripped.xm differ diff --git a/tests/taglib/data/sv4_header.mpc b/tests/taglib/data/sv4_header.mpc new file mode 100644 index 000000000..214f7ac4e Binary files /dev/null and b/tests/taglib/data/sv4_header.mpc differ diff --git a/tests/taglib/data/sv5_header.mpc b/tests/taglib/data/sv5_header.mpc new file mode 100644 index 000000000..6d17e65f0 Binary files /dev/null and b/tests/taglib/data/sv5_header.mpc differ diff --git a/tests/taglib/data/sv8_header.mpc b/tests/taglib/data/sv8_header.mpc new file mode 100644 index 000000000..3405545a2 Binary files /dev/null and b/tests/taglib/data/sv8_header.mpc differ diff --git a/tests/taglib/data/tagged.tta b/tests/taglib/data/tagged.tta new file mode 100644 index 000000000..1677a7edf Binary files /dev/null and b/tests/taglib/data/tagged.tta differ diff --git a/tests/taglib/data/tagged.wv b/tests/taglib/data/tagged.wv new file mode 100644 index 000000000..333f86871 Binary files /dev/null and b/tests/taglib/data/tagged.wv differ diff --git a/tests/taglib/data/test.it b/tests/taglib/data/test.it new file mode 100644 index 000000000..379444b91 Binary files /dev/null and b/tests/taglib/data/test.it differ diff --git a/tests/taglib/data/test.ogg b/tests/taglib/data/test.ogg new file mode 100644 index 000000000..220f76f0c Binary files /dev/null and b/tests/taglib/data/test.ogg differ diff --git a/tests/taglib/data/test.s3m b/tests/taglib/data/test.s3m new file mode 100644 index 000000000..668250bb7 Binary files /dev/null and b/tests/taglib/data/test.s3m differ diff --git a/tests/taglib/data/test.xm b/tests/taglib/data/test.xm new file mode 100644 index 000000000..b09d91324 Binary files /dev/null and b/tests/taglib/data/test.xm differ diff --git a/tests/taglib/data/toc_many_children.mp3 b/tests/taglib/data/toc_many_children.mp3 new file mode 100644 index 000000000..168c47981 Binary files /dev/null and b/tests/taglib/data/toc_many_children.mp3 differ diff --git a/tests/taglib/data/unsupported-extension.xx b/tests/taglib/data/unsupported-extension.xx new file mode 100644 index 000000000..65f57c2ee Binary files /dev/null and b/tests/taglib/data/unsupported-extension.xx differ diff --git a/tests/taglib/data/unsynch.id3 b/tests/taglib/data/unsynch.id3 new file mode 100644 index 000000000..cfe6ee1a6 Binary files /dev/null and b/tests/taglib/data/unsynch.id3 differ diff --git a/tests/taglib/data/w000.mp3 b/tests/taglib/data/w000.mp3 new file mode 100644 index 000000000..f9c226176 Binary files /dev/null and b/tests/taglib/data/w000.mp3 differ diff --git a/tests/taglib/data/xing.mp3 b/tests/taglib/data/xing.mp3 new file mode 100644 index 000000000..0c880151b Binary files /dev/null and b/tests/taglib/data/xing.mp3 differ diff --git a/tests/taglib/data/zero-length-mdat.m4a b/tests/taglib/data/zero-length-mdat.m4a new file mode 100644 index 000000000..578d2ef7a Binary files /dev/null and b/tests/taglib/data/zero-length-mdat.m4a differ diff --git a/tests/taglib/data/zero-size-chunk.wav b/tests/taglib/data/zero-size-chunk.wav new file mode 100644 index 000000000..8517e797d Binary files /dev/null and b/tests/taglib/data/zero-size-chunk.wav differ diff --git a/tests/taglib/data/zero-sized-padding.flac b/tests/taglib/data/zero-sized-padding.flac new file mode 100644 index 000000000..86ab8bf7b Binary files /dev/null and b/tests/taglib/data/zero-sized-padding.flac differ diff --git a/tests/taglib/data/zerodiv.ape b/tests/taglib/data/zerodiv.ape new file mode 100644 index 000000000..683bc2ddb Binary files /dev/null and b/tests/taglib/data/zerodiv.ape differ diff --git a/tests/taglib/data/zerodiv.mpc b/tests/taglib/data/zerodiv.mpc new file mode 100644 index 000000000..d3ea57c75 Binary files /dev/null and b/tests/taglib/data/zerodiv.mpc differ diff --git a/tests/taglib/main.cpp b/tests/taglib/main.cpp new file mode 100644 index 000000000..e4783b6c1 --- /dev/null +++ b/tests/taglib/main.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + std::string testPath = (argc > 1) ? std::string(argv[1]) : ""; + + // Create the event manager and test controller + CppUnit::TestResult controller; + + // Add a listener that collects test result + CppUnit::TestResultCollector result; + controller.addListener(&result); + + // Add a listener that print dots as test run. + CppUnit::BriefTestProgressListener progress; + controller.addListener(&progress); + + // Add the top suite to the test runner + CppUnit::TestRunner runner; + runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); + + try { + std::cout << "Running " << testPath; + runner.run(controller, testPath); + + std::cerr << std::endl; + + // Print test in a compiler compatible format. + CppUnit::CompilerOutputter outputter(&result, std::cerr); + outputter.write(); + +#if defined(_MSC_VER) && _MSC_VER > 1500 + char *xml = NULL; + ::_dupenv_s(&xml, NULL, "CPPUNIT_XML"); +#else + char *xml = ::getenv("CPPUNIT_XML"); +#endif + if (xml && !::strcmp(xml, "1")) { + std::ofstream xmlfileout("cpptestresults.xml"); + CppUnit::XmlOutputter xmlout(&result, xmlfileout); + xmlout.write(); + } +#if defined(_MSC_VER) && _MSC_VER > 1500 + ::free(xml); +#endif + } catch (std::invalid_argument &e) { + std::cerr << std::endl + << "ERROR: " << e.what() + << std::endl; + return 0; + } + + return result.wasSuccessful() ? 0 : 1; +} diff --git a/tests/taglib/test_aiff.cpp b/tests/taglib/test_aiff.cpp new file mode 100644 index 000000000..d80dff25b --- /dev/null +++ b/tests/taglib/test_aiff.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tbytevectorlist.h" +#include "aifffile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestAIFF : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestAIFF); + CPPUNIT_TEST(testAiffProperties); + CPPUNIT_TEST(testAiffCProperties); + CPPUNIT_TEST(testSaveID3v2); + CPPUNIT_TEST(testDuplicateID3v2); + CPPUNIT_TEST(testFuzzedFile1); + CPPUNIT_TEST(testFuzzedFile2); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAiffProperties() { + RIFF::AIFF::File f(TEST_FILE_PATH_C("empty.aiff")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(67, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(706, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(2941U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isAiffC()); + } + + void testAiffCProperties() { + RIFF::AIFF::File f(TEST_FILE_PATH_C("alaw.aifc")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(37, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(355, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(1622U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(true, f.audioProperties()->isAiffC()); + CPPUNIT_ASSERT_EQUAL(ByteVector("ALAW"), f.audioProperties()->compressionType()); + CPPUNIT_ASSERT_EQUAL(String("SGI CCITT G.711 A-law"), f.audioProperties()->compressionName()); + } + + void testSaveID3v2() { + ScopedFileCopy copy("empty", ".aiff"); + string newname = copy.fileName(); + + { + RIFF::AIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + + f.tag()->setTitle(L"TitleXXX"); + f.save(); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + } + { + RIFF::AIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String(L"TitleXXX"), f.tag()->title()); + + f.tag()->setTitle(""); + f.save(); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + { + RIFF::AIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + } + + void testDuplicateID3v2() { + ScopedFileCopy copy("duplicate_id3v2", ".aiff"); + + // duplicate_id3v2.aiff has duplicate ID3v2 tag chunks. + // title() returns "Title2" if can't skip the second tag. + + RIFF::AIFF::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String("Title1"), f.tag()->title()); + + f.save(); + CPPUNIT_ASSERT_EQUAL(7030LL, f.length()); + CPPUNIT_ASSERT_EQUAL(-1LL, f.find("Title2")); + } + + void testFuzzedFile1() { + RIFF::AIFF::File f(TEST_FILE_PATH_C("segfault.aif")); + CPPUNIT_ASSERT(!f.isValid()); + } + + void testFuzzedFile2() { + RIFF::AIFF::File f(TEST_FILE_PATH_C("excessive_alloc.aif")); + CPPUNIT_ASSERT(!f.isValid()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestAIFF); diff --git a/tests/taglib/test_ape.cpp b/tests/taglib/test_ape.cpp new file mode 100644 index 000000000..fdac57145 --- /dev/null +++ b/tests/taglib/test_ape.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + copyright : (C) 2010 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "apetag.h" +#include "id3v1tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "apefile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestAPE : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestAPE); + CPPUNIT_TEST(testProperties399); + CPPUNIT_TEST(testProperties399Tagged); + CPPUNIT_TEST(testProperties399Id3v2); + CPPUNIT_TEST(testProperties396); + CPPUNIT_TEST(testProperties390); + CPPUNIT_TEST(testFuzzedFile1); + CPPUNIT_TEST(testFuzzedFile2); + CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST_SUITE_END(); + + public: + void testProperties399() { + APE::File f(TEST_FILE_PATH_C("mac-399.ape")); + CPPUNIT_ASSERT(f.audioProperties());; + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3550, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(192, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(156556U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(3990, f.audioProperties()->version()); + } + + void testProperties399Tagged() { + APE::File f(TEST_FILE_PATH_C("mac-399-tagged.ape")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3550, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(192, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(156556U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(3990, f.audioProperties()->version()); + } + + void testProperties399Id3v2() { + APE::File f(TEST_FILE_PATH_C("mac-399-id3v2.ape")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3550, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(192, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(156556U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(3990, f.audioProperties()->version()); + } + + void testProperties396() { + APE::File f(TEST_FILE_PATH_C("mac-396.ape")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(162496U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(3960, f.audioProperties()->version()); + } + + void testProperties390() { + APE::File f(TEST_FILE_PATH_C("mac-390-hdr.ape")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(15, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(15630, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(689262U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(3900, f.audioProperties()->version()); + } + + void testFuzzedFile1() { + APE::File f(TEST_FILE_PATH_C("longloop.ape")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testFuzzedFile2() { + APE::File f(TEST_FILE_PATH_C("zerodiv.ape")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testStripAndProperties() { + ScopedFileCopy copy("mac-399", ".ape"); + + { + APE::File f(copy.fileName().c_str()); + f.APETag(true)->setTitle("APE"); + f.ID3v1Tag(true)->setTitle("ID3v1"); + f.save(); + } + { + APE::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("APE"), f.properties()["TITLE"].front()); + f.strip(APE::File::APE); + CPPUNIT_ASSERT_EQUAL(String("ID3v1"), f.properties()["TITLE"].front()); + f.strip(APE::File::ID3v1); + CPPUNIT_ASSERT(f.properties().isEmpty()); + } + } + + void testRepeatedSave() { + ScopedFileCopy copy("mac-399", ".ape"); + + { + APE::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasAPETag()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + + f.APETag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.save(); + + f.APETag()->setTitle("0"); + f.save(); + + f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.APETag()->setTitle("01234 56789 ABCDE FGHIJ 01234 56789 ABCDE FGHIJ 01234 56789"); + f.save(); + } + { + APE::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasAPETag()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestAPE); diff --git a/tests/taglib/test_apetag.cpp b/tests/taglib/test_apetag.cpp new file mode 100644 index 000000000..4253eab59 --- /dev/null +++ b/tests/taglib/test_apetag.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + copyright : (C) 2010 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "apetag.h" +#include "tdebug.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestAPETag : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestAPETag); + CPPUNIT_TEST(testIsEmpty); + CPPUNIT_TEST(testIsEmpty2); + CPPUNIT_TEST(testPropertyInterface1); + CPPUNIT_TEST(testPropertyInterface2); + CPPUNIT_TEST(testInvalidKeys); + CPPUNIT_TEST(testTextBinary); + CPPUNIT_TEST_SUITE_END(); + + public: + void testIsEmpty() { + APE::Tag tag; + CPPUNIT_ASSERT(tag.isEmpty()); + tag.addValue("COMPOSER", "Mike Oldfield"); + CPPUNIT_ASSERT(!tag.isEmpty()); + } + + void testIsEmpty2() { + APE::Tag tag; + CPPUNIT_ASSERT(tag.isEmpty()); + tag.setArtist("Mike Oldfield"); + CPPUNIT_ASSERT(!tag.isEmpty()); + } + + void testPropertyInterface1() { + APE::Tag tag; + PropertyMap dict = tag.properties(); + CPPUNIT_ASSERT(dict.isEmpty()); + dict["ARTIST"] = String("artist 1"); + dict["ARTIST"].append("artist 2"); + dict["TRACKNUMBER"].append("17"); + tag.setProperties(dict); + CPPUNIT_ASSERT_EQUAL(String("17"), tag.itemListMap()["TRACK"].values()[0]); + CPPUNIT_ASSERT_EQUAL((size_t)2, tag.itemListMap()["ARTIST"].values().size()); + CPPUNIT_ASSERT_EQUAL(String("artist 1 artist 2"), tag.artist()); + CPPUNIT_ASSERT_EQUAL(17u, tag.track()); + } + + void testPropertyInterface2() { + APE::Tag tag; + APE::Item item1 = APE::Item("TRACK", "17"); + tag.setItem("TRACK", item1); + + APE::Item item2 = APE::Item(); + item2.setType(APE::Item::Binary); + tag.setItem("TESTBINARY", item2); + + PropertyMap properties = tag.properties(); + CPPUNIT_ASSERT_EQUAL((size_t)1u, properties.unsupportedData().size()); + CPPUNIT_ASSERT(properties.contains("TRACKNUMBER")); + CPPUNIT_ASSERT(!properties.contains("TRACK")); + CPPUNIT_ASSERT(tag.itemListMap().contains("TESTBINARY")); + + tag.removeUnsupportedProperties(properties.unsupportedData()); + CPPUNIT_ASSERT(!tag.itemListMap().contains("TESTBINARY")); + + APE::Item item3 = APE::Item("TRACKNUMBER", "29"); + tag.setItem("TRACKNUMBER", item3); + properties = tag.properties(); + CPPUNIT_ASSERT_EQUAL((size_t)2, properties["TRACKNUMBER"].size()); + CPPUNIT_ASSERT_EQUAL(String("17"), properties["TRACKNUMBER"][0]); + CPPUNIT_ASSERT_EQUAL(String("29"), properties["TRACKNUMBER"][1]); + } + + void testInvalidKeys() { + PropertyMap properties; + properties["A"] = String("invalid key: one character"); + properties["MP+"] = String("invalid key: forbidden string"); + properties[L"\x1234\x3456"] = String("invalid key: Unicode"); + properties["A B~C"] = String("valid key: space and tilde"); + properties["ARTIST"] = String("valid key: normal one"); + + APE::Tag tag; + PropertyMap unsuccessful = tag.setProperties(properties); + CPPUNIT_ASSERT_EQUAL((size_t)3, unsuccessful.size()); + CPPUNIT_ASSERT(unsuccessful.contains("A")); + CPPUNIT_ASSERT(unsuccessful.contains("MP+")); + CPPUNIT_ASSERT(unsuccessful.contains(L"\x1234\x3456")); + + CPPUNIT_ASSERT_EQUAL((size_t)2, tag.itemListMap().size()); + tag.addValue("VALID KEY", "Test Value 1"); + tag.addValue("INVALID KEY \x7f", "Test Value 2"); + tag.addValue(L"INVALID KEY \x1234\x3456", "Test Value 3"); + CPPUNIT_ASSERT_EQUAL((size_t)3, tag.itemListMap().size()); + } + + void testTextBinary() { + APE::Item item = APE::Item("DUMMY", "Test Text"); + CPPUNIT_ASSERT_EQUAL(String("Test Text"), item.toString()); + CPPUNIT_ASSERT_EQUAL(ByteVector(), item.binaryData()); + + ByteVector data("Test Data"); + item.setBinaryData(data); + CPPUNIT_ASSERT(item.values().isEmpty()); + CPPUNIT_ASSERT_EQUAL(String(), item.toString()); + CPPUNIT_ASSERT_EQUAL(data, item.binaryData()); + + item.setValue("Test Text 2"); + CPPUNIT_ASSERT_EQUAL(String("Test Text 2"), item.toString()); + CPPUNIT_ASSERT_EQUAL(ByteVector(), item.binaryData()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestAPETag); diff --git a/tests/taglib/test_asf.cpp b/tests/taglib/test_asf.cpp new file mode 100644 index 000000000..d897045f4 --- /dev/null +++ b/tests/taglib/test_asf.cpp @@ -0,0 +1,306 @@ +/*************************************************************************** + copyright : (C) 2008 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstring.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "asffile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestASF : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestASF); + CPPUNIT_TEST(testAudioProperties); + CPPUNIT_TEST(testLosslessProperties); + CPPUNIT_TEST(testRead); + CPPUNIT_TEST(testSaveMultipleValues); + CPPUNIT_TEST(testSaveStream); + CPPUNIT_TEST(testSaveLanguage); + CPPUNIT_TEST(testDWordTrackNumber); +// CPPUNIT_TEST(testSaveLargeValue); + CPPUNIT_TEST(testSavePicture); + CPPUNIT_TEST(testSaveMultiplePictures); + CPPUNIT_TEST(testProperties); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAudioProperties() { + ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3712, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(ASF::AudioProperties::WMA2, f.audioProperties()->codec()); + CPPUNIT_ASSERT_EQUAL(String("Windows Media Audio 9.1"), f.audioProperties()->codecName()); + CPPUNIT_ASSERT_EQUAL(String("64 kbps, 48 kHz, stereo 2-pass CBR"), f.audioProperties()->codecDescription()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + } + + void testLosslessProperties() { + ASF::File f(TEST_FILE_PATH_C("lossless.wma")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3549, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(1152, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(ASF::AudioProperties::WMA9Lossless, f.audioProperties()->codec()); + CPPUNIT_ASSERT_EQUAL(String("Windows Media Audio 9.2 Lossless"), f.audioProperties()->codecName()); + CPPUNIT_ASSERT_EQUAL(String("VBR Quality 100, 44 kHz, 2 channel 16 bit 1-pass VBR"), f.audioProperties()->codecDescription()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + } + + void testRead() { + ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); + CPPUNIT_ASSERT_EQUAL(String("test"), f.tag()->title()); + } + + void testSaveMultipleValues() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + ASF::AttributeList values; + values.append("Foo"); + values.append("Bar"); + f.tag()->setAttribute("WM/AlbumTitle", values); + f.save(); + } + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(2, (int)f.tag()->attributeListMap()["WM/AlbumTitle"].size()); + } + } + + void testDWordTrackNumber() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.tag()->contains("WM/TrackNumber")); + f.tag()->setAttribute("WM/TrackNumber", static_cast(123)); + f.save(); + } + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT(f.tag()->contains("WM/TrackNumber")); + CPPUNIT_ASSERT_EQUAL(ASF::Attribute::DWordType, f.tag()->attribute("WM/TrackNumber").front().type()); + CPPUNIT_ASSERT_EQUAL(static_cast(123), f.tag()->track()); + f.tag()->setTrack(234); + f.save(); + } + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT(f.tag()->contains("WM/TrackNumber")); + CPPUNIT_ASSERT_EQUAL(ASF::Attribute::UnicodeType, f.tag()->attribute("WM/TrackNumber").front().type()); + CPPUNIT_ASSERT_EQUAL((unsigned int)234, f.tag()->track()); + } + } + + void testSaveStream() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + ASF::Attribute attr("Foo"); + attr.setStream(43); + f.tag()->setAttribute("WM/AlbumTitle", attr); + f.save(); + } + + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(43, f.tag()->attribute("WM/AlbumTitle").front().stream()); + } + } + + void testSaveLanguage() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + ASF::Attribute attr("Foo"); + attr.setStream(32); + attr.setLanguage(56); + f.tag()->setAttribute("WM/AlbumTitle", attr); + f.save(); + } + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(32, f.tag()->attribute("WM/AlbumTitle").front().stream()); + CPPUNIT_ASSERT_EQUAL(56, f.tag()->attribute("WM/AlbumTitle").front().language()); + } + } + + void testSaveLargeValue() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + ASF::Attribute attr(ByteVector(70000, 'x')); + f.tag()->setAttribute("WM/Blob", attr); + f.save(); + } + { + ASF::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(ByteVector(70000, 'x'), f.tag()->attribute("WM/Blob").front().toByteVector()); + } + } + + void testSavePicture() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + ASF::Picture picture; + picture.setMimeType("image/jpeg"); + picture.setType(ASF::Picture::FrontCover); + picture.setDescription("description"); + picture.setPicture("data"); + f.tag()->setAttribute("WM/Picture", picture); + f.save(); + } + { + ASF::File f(newname.c_str()); + ASF::AttributeList values2 = f.tag()->attribute("WM/Picture"); + CPPUNIT_ASSERT_EQUAL((size_t)1, values2.size()); + ASF::Attribute attr2 = values2.front(); + ASF::Picture picture2 = attr2.toPicture(); + CPPUNIT_ASSERT(picture2.isValid()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture2.mimeType()); + CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture2.type()); + CPPUNIT_ASSERT_EQUAL(String("description"), picture2.description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture2.picture()); + } + } + + void testSaveMultiplePictures() { + ScopedFileCopy copy("silence-1", ".wma"); + string newname = copy.fileName(); + + { + ASF::File f(newname.c_str()); + ASF::AttributeList values; + ASF::Picture picture; + picture.setMimeType("image/jpeg"); + picture.setType(ASF::Picture::FrontCover); + picture.setDescription("description"); + picture.setPicture("data"); + values.append(ASF::Attribute(picture)); + ASF::Picture picture2; + picture2.setMimeType("image/png"); + picture2.setType(ASF::Picture::BackCover); + picture2.setDescription("back cover"); + picture2.setPicture("PNG data"); + values.append(ASF::Attribute(picture2)); + f.tag()->setAttribute("WM/Picture", values); + f.save(); + } + { + ASF::File f(newname.c_str()); + ASF::AttributeList values2 = f.tag()->attribute("WM/Picture"); + CPPUNIT_ASSERT_EQUAL((size_t)2, values2.size()); + ASF::Picture picture3 = values2[1].toPicture(); + CPPUNIT_ASSERT(picture3.isValid()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture3.mimeType()); + CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture3.type()); + CPPUNIT_ASSERT_EQUAL(String("description"), picture3.description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture3.picture()); + ASF::Picture picture4 = values2[0].toPicture(); + CPPUNIT_ASSERT(picture4.isValid()); + CPPUNIT_ASSERT_EQUAL(String("image/png"), picture4.mimeType()); + CPPUNIT_ASSERT_EQUAL(ASF::Picture::BackCover, picture4.type()); + CPPUNIT_ASSERT_EQUAL(String("back cover"), picture4.description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("PNG data"), picture4.picture()); + } + } + + void testProperties() { + ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); + + PropertyMap tags = f.properties(); + + tags["TRACKNUMBER"] = StringList("2"); + tags["DISCNUMBER"] = StringList("3"); + tags["BPM"] = StringList("123"); + tags["ARTIST"] = StringList("Foo Bar"); + f.setProperties(tags); + + tags = f.properties(); + + CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), f.tag()->artist()); + CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]); + + CPPUNIT_ASSERT(f.tag()->contains("WM/BeatsPerMinute")); + CPPUNIT_ASSERT_EQUAL((size_t)1, f.tag()->attributeListMap()["WM/BeatsPerMinute"].size()); + CPPUNIT_ASSERT_EQUAL(String("123"), f.tag()->attribute("WM/BeatsPerMinute").front().toString()); + CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]); + + CPPUNIT_ASSERT(f.tag()->contains("WM/TrackNumber")); + CPPUNIT_ASSERT_EQUAL((size_t)1, f.tag()->attributeListMap()["WM/TrackNumber"].size()); + CPPUNIT_ASSERT_EQUAL(String("2"), f.tag()->attribute("WM/TrackNumber").front().toString()); + CPPUNIT_ASSERT_EQUAL(StringList("2"), tags["TRACKNUMBER"]); + + CPPUNIT_ASSERT(f.tag()->contains("WM/PartOfSet")); + CPPUNIT_ASSERT_EQUAL((size_t)1, f.tag()->attributeListMap()["WM/PartOfSet"].size()); + CPPUNIT_ASSERT_EQUAL(String("3"), f.tag()->attribute("WM/PartOfSet").front().toString()); + CPPUNIT_ASSERT_EQUAL(StringList("3"), tags["DISCNUMBER"]); + } + + void testRepeatedSave() { + ScopedFileCopy copy("silence-1", ".wma"); + + { + ASF::File f(copy.fileName().c_str()); + f.tag()->setTitle(longText(128 * 1024)); + f.save(); + CPPUNIT_ASSERT_EQUAL(297578LL, f.length()); + f.tag()->setTitle(longText(16 * 1024)); + f.save(); + CPPUNIT_ASSERT_EQUAL(68202LL, f.length()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestASF); diff --git a/tests/taglib/test_bytevector.cpp b/tests/taglib/test_bytevector.cpp new file mode 100644 index 000000000..5ea208fb1 --- /dev/null +++ b/tests/taglib/test_bytevector.cpp @@ -0,0 +1,579 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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/ * + ***************************************************************************/ + +#define _USE_MATH_DEFINES +#include +#include + +#include "tbytevector.h" +#include "tbytevectorlist.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestByteVector : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestByteVector); + CPPUNIT_TEST(testByteVector); + CPPUNIT_TEST(testFind1); + CPPUNIT_TEST(testFind2); + CPPUNIT_TEST(testFind3); + CPPUNIT_TEST(testRfind1); + CPPUNIT_TEST(testRfind2); + CPPUNIT_TEST(testRfind3); + CPPUNIT_TEST(testToHex); + CPPUNIT_TEST(testIntegerConversion); + CPPUNIT_TEST(testFloatingPointConversion); + CPPUNIT_TEST(testReplace); + CPPUNIT_TEST(testReplaceAndDetach); + CPPUNIT_TEST(testIterator); + CPPUNIT_TEST(testResize); + CPPUNIT_TEST(testAppend1); + CPPUNIT_TEST(testAppend2); + CPPUNIT_TEST(testBase64); + CPPUNIT_TEST_SUITE_END(); + + public: + void testByteVector() { + ByteVector s1("foo"); + CPPUNIT_ASSERT(ByteVectorList::split(s1, " ").size() == 1); + + ByteVector s2("f"); + CPPUNIT_ASSERT(ByteVectorList::split(s2, " ").size() == 1); + + CPPUNIT_ASSERT(ByteVector().isEmpty()); + CPPUNIT_ASSERT_EQUAL((size_t)0, ByteVector().size()); + CPPUNIT_ASSERT(ByteVector("asdf").clear().isEmpty()); + CPPUNIT_ASSERT_EQUAL((size_t)0, ByteVector("asdf").clear().size()); + CPPUNIT_ASSERT_EQUAL(ByteVector(), ByteVector("asdf").clear()); + + ByteVector i("blah blah"); + ByteVector j("blah"); + CPPUNIT_ASSERT(i.containsAt(j, 5, 0)); + CPPUNIT_ASSERT(i.containsAt(j, 6, 1)); + CPPUNIT_ASSERT(i.containsAt(j, 6, 1, 3)); + + i.clear(); + CPPUNIT_ASSERT(i.isEmpty()); + } + + void testFind1() { + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find("SggO")); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find("SggO", 0)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find("SggO", 1)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find("SggO", 2)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find("SggO", 3)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find("SggO", 4)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find("SggO", 5)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find("SggO", 6)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find("SggO", 7)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find("SggO", 8)); + + // Intentional out-of-bounds access. + ByteVector v("0123456789x"); + v.resize(10); + v.data()[10] = 'x'; + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), v.find("789x", 7)); + } + + void testFind2() { + CPPUNIT_ASSERT_EQUAL((size_t)0, ByteVector("\x01", 1).find("\x01")); + CPPUNIT_ASSERT_EQUAL((size_t)0, ByteVector("\x01\x02", 2).find("\x01\x02")); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("\x01", 1).find("\x02")); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("\x01\x02", 2).find("\x01\x03")); + } + + void testFind3() { + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find('S')); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find('S', 0)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find('S', 1)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find('S', 2)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find('S', 3)); + CPPUNIT_ASSERT_EQUAL((size_t)4, ByteVector("....SggO.").find('S', 4)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find('S', 5)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find('S', 6)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find('S', 7)); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), ByteVector("....SggO.").find('S', 8)); + } + + void testRfind1() { + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 0)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 1)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 2)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 3)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 4)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 5)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 6)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 7)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS", 8)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind("OggS")); + } + + void testRfind2() { + ByteVector r0("**************"); + ByteVector r1("OggS**********"); + ByteVector r2("**********OggS"); + ByteVector r3("OggS******OggS"); + ByteVector r4("OggS*OggS*OggS"); + + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), r0.find("OggS")); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), r0.rfind("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)0, r1.find("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)0, r1.rfind("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)10, r2.find("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)10, r2.rfind("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)0, r3.find("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)10, r3.rfind("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)10, r4.rfind("OggS")); + CPPUNIT_ASSERT_EQUAL((size_t)10, r4.rfind("OggS", 0)); + CPPUNIT_ASSERT_EQUAL((size_t)5, r4.rfind("OggS", 7)); + CPPUNIT_ASSERT_EQUAL((size_t)10, r4.rfind("OggS", 12)); + } + + void testRfind3() { + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 0)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 1)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 2)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 3)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 4)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 5)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 6)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 7)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O', 8)); + CPPUNIT_ASSERT_EQUAL((size_t)1, ByteVector(".OggS....").rfind('O')); + } + + void testToHex() { + ByteVector v("\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f", 16); + + CPPUNIT_ASSERT_EQUAL(ByteVector("f0e1d2c3b4a5968778695a4b3c2d1e0f"), v.toHex()); + } + + void testIntegerConversion() { + const ByteVector data("\x00\xff\x01\xff\x00\xff\x01\xff\x00\xff\x01\xff\x00\xff", 14); + + CPPUNIT_ASSERT_EQUAL((short)0x00ff, data.toInt16BE(0)); + CPPUNIT_ASSERT_EQUAL((short)0xff00, data.toInt16LE(0)); + CPPUNIT_ASSERT_EQUAL((short)0xff01, data.toInt16BE(5)); + CPPUNIT_ASSERT_EQUAL((short)0x01ff, data.toInt16LE(5)); + CPPUNIT_ASSERT_EQUAL((short)0xff, data.toInt16BE(13)); + CPPUNIT_ASSERT_EQUAL((short)0xff, data.toInt16LE(13)); + + CPPUNIT_ASSERT_EQUAL((unsigned short)0x00ff, data.toUInt16BE(0)); + CPPUNIT_ASSERT_EQUAL((unsigned short)0xff00, data.toUInt16LE(0)); + CPPUNIT_ASSERT_EQUAL((unsigned short)0xff01, data.toUInt16BE(5)); + CPPUNIT_ASSERT_EQUAL((unsigned short)0x01ff, data.toUInt16LE(5)); + CPPUNIT_ASSERT_EQUAL((unsigned short)0xff, data.toUInt16BE(13)); + CPPUNIT_ASSERT_EQUAL((unsigned short)0xff, data.toUInt16LE(13)); + + CPPUNIT_ASSERT_EQUAL(0x00ff01ffU, data.toUInt32BE(0)); + CPPUNIT_ASSERT_EQUAL(0xff01ff00U, data.toUInt32LE(0)); + CPPUNIT_ASSERT_EQUAL(0xff01ff00U, data.toUInt32BE(5)); + CPPUNIT_ASSERT_EQUAL(0x00ff01ffU, data.toUInt32LE(5)); + CPPUNIT_ASSERT_EQUAL(0x00ffU, data.toUInt32BE(12)); + CPPUNIT_ASSERT_EQUAL(0xff00U, data.toUInt32LE(12)); + + CPPUNIT_ASSERT_EQUAL(0x00ff01U, data.toUInt24BE(0)); + CPPUNIT_ASSERT_EQUAL(0x01ff00U, data.toUInt24LE(0)); + CPPUNIT_ASSERT_EQUAL(0xff01ffU, data.toUInt24BE(5)); + CPPUNIT_ASSERT_EQUAL(0xff01ffU, data.toUInt24LE(5)); + CPPUNIT_ASSERT_EQUAL(0x00ffU, data.toUInt24BE(12)); + CPPUNIT_ASSERT_EQUAL(0xff00U, data.toUInt24LE(12)); + + CPPUNIT_ASSERT_EQUAL((long long)0x00ff01ff00ff01ffULL, data.toInt64BE(0)); + CPPUNIT_ASSERT_EQUAL((long long)0xff01ff00ff01ff00ULL, data.toInt64LE(0)); + CPPUNIT_ASSERT_EQUAL((long long)0xff01ff00ff01ff00ULL, data.toInt64BE(5)); + CPPUNIT_ASSERT_EQUAL((long long)0x00ff01ff00ff01ffULL, data.toInt64LE(5)); + CPPUNIT_ASSERT_EQUAL((long long)0x00ffU, data.toInt64BE(12)); + CPPUNIT_ASSERT_EQUAL((long long)0xff00U, data.toInt64LE(12)); + } + + void testFloatingPointConversion() { + const double Tolerance = 1.0e-7; + + const ByteVector pi32le("\xdb\x0f\x49\x40", 4); + CPPUNIT_ASSERT(std::abs(pi32le.toFloat32LE(0) - M_PI) < Tolerance); + CPPUNIT_ASSERT_EQUAL(pi32le, ByteVector::fromFloat32LE(pi32le.toFloat32LE(0))); + + const ByteVector pi32be("\x40\x49\x0f\xdb", 4); + CPPUNIT_ASSERT(std::abs(pi32be.toFloat32BE(0) - M_PI) < Tolerance); + CPPUNIT_ASSERT_EQUAL(pi32be, ByteVector::fromFloat32BE(pi32be.toFloat32BE(0))); + + const ByteVector pi64le("\x18\x2d\x44\x54\xfb\x21\x09\x40", 8); + CPPUNIT_ASSERT(std::abs(pi64le.toFloat64LE(0) - M_PI) < Tolerance); + CPPUNIT_ASSERT_EQUAL(pi64le, ByteVector::fromFloat64LE(pi64le.toFloat64LE(0))); + + const ByteVector pi64be("\x40\x09\x21\xfb\x54\x44\x2d\x18", 8); + CPPUNIT_ASSERT(std::abs(pi64be.toFloat64BE(0) - M_PI) < Tolerance); + CPPUNIT_ASSERT_EQUAL(pi64be, ByteVector::fromFloat64BE(pi64be.toFloat64BE(0))); + + const ByteVector pi80le("\x00\xc0\x68\x21\xa2\xda\x0f\xc9\x00\x40", 10); + CPPUNIT_ASSERT(std::abs(pi80le.toFloat80LE(0) - M_PI) < Tolerance); + + const ByteVector pi80be("\x40\x00\xc9\x0f\xda\xa2\x21\x68\xc0\x00", 10); + CPPUNIT_ASSERT(std::abs(pi80be.toFloat80BE(0) - M_PI) < Tolerance); + } + + void testReplace() { + { + ByteVector a("abcdabf"); + a.replace(ByteVector(""), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace(ByteVector("foobartoolong"), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace(ByteVector("xx"), ByteVector("yy")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace(ByteVector("a"), ByteVector("x")); + CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a); + a.replace(ByteVector("x"), ByteVector("a")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace('a', 'x'); + CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a); + a.replace('x', 'a'); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace(ByteVector("ab"), ByteVector("xy")); + CPPUNIT_ASSERT_EQUAL(ByteVector("xycdxyf"), a); + a.replace(ByteVector("xy"), ByteVector("ab")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace(ByteVector("a"), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("bcdbf"), a); + a.replace(ByteVector(""), ByteVector("a")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabf"); + a.replace(ByteVector("b"), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("acdaf"), a); + a.replace(ByteVector(""), ByteVector("b")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); + } + { + ByteVector a("abcdabc"); + a.replace(ByteVector("c"), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abdab"), a); + a.replace(ByteVector(""), ByteVector("c")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabc"), a); + } + { + ByteVector a("abcdaba"); + a.replace(ByteVector("a"), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("bcdb"), a); + a.replace(ByteVector(""), ByteVector("a")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdaba"), a); + } + } + + void testReplaceAndDetach() { + { + ByteVector a("abcdabf"); + ByteVector b = a; + a.replace(ByteVector("a"), ByteVector("x")); + CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b); + } + { + ByteVector a("abcdabf"); + ByteVector b = a; + a.replace('a', 'x'); + CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b); + } + { + ByteVector a("abcdabf"); + ByteVector b = a; + a.replace(ByteVector("ab"), ByteVector("xy")); + CPPUNIT_ASSERT_EQUAL(ByteVector("xycdxyf"), a); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b); + } + { + ByteVector a("abcdabf"); + ByteVector b = a; + a.replace(ByteVector("a"), ByteVector("")); + CPPUNIT_ASSERT_EQUAL(ByteVector("bcdbf"), a); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b); + } + { + ByteVector a("abdab"); + ByteVector b = a; + a.replace(ByteVector(""), ByteVector("c")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabc"), a); + CPPUNIT_ASSERT_EQUAL(ByteVector("abdab"), b); + } + } + + void testIterator() { + ByteVector v1("taglib"); + ByteVector v2 = v1; + + ByteVector::Iterator it1 = v1.begin(); + ByteVector::Iterator it2 = v2.begin(); + + CPPUNIT_ASSERT_EQUAL('t', *it1); + CPPUNIT_ASSERT_EQUAL('t', *it2); + + std::advance(it1, 4); + std::advance(it2, 4); + *it2 = 'I'; + CPPUNIT_ASSERT_EQUAL('i', *it1); + CPPUNIT_ASSERT_EQUAL('I', *it2); + CPPUNIT_ASSERT_EQUAL(ByteVector("taglib"), v1); + CPPUNIT_ASSERT_EQUAL(ByteVector("taglIb"), v2); + + ByteVector::ReverseIterator it3 = v1.rbegin(); + ByteVector::ReverseIterator it4 = v2.rbegin(); + + CPPUNIT_ASSERT_EQUAL('b', *it3); + CPPUNIT_ASSERT_EQUAL('b', *it4); + + std::advance(it3, 4); + std::advance(it4, 4); + *it4 = 'A'; + CPPUNIT_ASSERT_EQUAL('a', *it3); + CPPUNIT_ASSERT_EQUAL('A', *it4); + CPPUNIT_ASSERT_EQUAL(ByteVector("taglib"), v1); + CPPUNIT_ASSERT_EQUAL(ByteVector("tAglIb"), v2); + + ByteVector v3; + v3 = ByteVector("0123456789").mid(3, 4); + + it1 = v3.begin(); + it2 = v3.end() - 1; + CPPUNIT_ASSERT_EQUAL('3', *it1); + CPPUNIT_ASSERT_EQUAL('6', *it2); + + it3 = v3.rbegin(); + it4 = v3.rend() - 1; + CPPUNIT_ASSERT_EQUAL('6', *it3); + CPPUNIT_ASSERT_EQUAL('3', *it4); + } + + void testResize() { + ByteVector a = ByteVector("0123456789"); + ByteVector b = a.mid(3, 4); + b.resize(6, 'A'); + CPPUNIT_ASSERT_EQUAL((size_t)6, b.size()); + CPPUNIT_ASSERT_EQUAL('6', b[3]); + CPPUNIT_ASSERT_EQUAL('A', b[4]); + CPPUNIT_ASSERT_EQUAL('A', b[5]); + b.resize(10, 'B'); + CPPUNIT_ASSERT_EQUAL((size_t)10, b.size()); + CPPUNIT_ASSERT_EQUAL('6', b[3]); + CPPUNIT_ASSERT_EQUAL('B', b[6]); + CPPUNIT_ASSERT_EQUAL('B', b[9]); + b.resize(3, 'C'); + CPPUNIT_ASSERT_EQUAL((size_t)3, b.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), b.find('C')); + b.resize(3); + CPPUNIT_ASSERT_EQUAL((size_t)3, b.size()); + + // Check if a and b were properly detached. + + CPPUNIT_ASSERT_EQUAL((size_t)10, a.size()); + CPPUNIT_ASSERT_EQUAL('3', a[3]); + CPPUNIT_ASSERT_EQUAL('5', a[5]); + + // Special case that refCount == 1 and d->offset != 0. + + ByteVector c = ByteVector("0123456789").mid(3, 4); + c.resize(6, 'A'); + CPPUNIT_ASSERT_EQUAL(size_t(6), c.size()); + CPPUNIT_ASSERT_EQUAL('6', c[3]); + CPPUNIT_ASSERT_EQUAL('A', c[4]); + CPPUNIT_ASSERT_EQUAL('A', c[5]); + c.resize(10, 'B'); + CPPUNIT_ASSERT_EQUAL((size_t)10, c.size()); + CPPUNIT_ASSERT_EQUAL('6', c[3]); + CPPUNIT_ASSERT_EQUAL('B', c[6]); + CPPUNIT_ASSERT_EQUAL('B', c[9]); + c.resize(3, 'C'); + CPPUNIT_ASSERT_EQUAL((size_t)3, c.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector::npos(), c.find('C')); + } + + void testAppend1() { + ByteVector v1("foo"); + v1.append("bar"); + CPPUNIT_ASSERT_EQUAL(ByteVector("foobar"), v1); + + ByteVector v2("foo"); + v2.append("b"); + CPPUNIT_ASSERT_EQUAL(ByteVector("foob"), v2); + + ByteVector v3; + v3.append("b"); + CPPUNIT_ASSERT_EQUAL(ByteVector("b"), v3); + + ByteVector v4("foo"); + v4.append(v1); + CPPUNIT_ASSERT_EQUAL(ByteVector("foofoobar"), v4); + + ByteVector v5("foo"); + v5.append('b'); + CPPUNIT_ASSERT_EQUAL(ByteVector("foob"), v5); + + ByteVector v6; + v6.append('b'); + CPPUNIT_ASSERT_EQUAL(ByteVector("b"), v6); + + ByteVector v7("taglib"); + ByteVector v8 = v7; + + v7.append("ABC"); + CPPUNIT_ASSERT_EQUAL(ByteVector("taglibABC"), v7); + v7.append('1'); + v7.append('2'); + v7.append('3'); + CPPUNIT_ASSERT_EQUAL(ByteVector("taglibABC123"), v7); + CPPUNIT_ASSERT_EQUAL(ByteVector("taglib"), v8); + } + + void testAppend2() { + ByteVector a("1234"); + a.append(a); + CPPUNIT_ASSERT_EQUAL(ByteVector("12341234"), a); + } + + void testBase64() { + ByteVector sempty; + ByteVector t0("a"); // test 1 byte + ByteVector t1("any carnal pleasure."); + ByteVector t2("any carnal pleasure"); + ByteVector t3("any carnal pleasur"); + ByteVector s0("a"); // test 1 byte + ByteVector s1("any carnal pleasure."); + ByteVector s2("any carnal pleasure"); + ByteVector s3("any carnal pleasur"); + ByteVector eempty; + ByteVector e0("YQ=="); + ByteVector e1("YW55IGNhcm5hbCBwbGVhc3VyZS4="); + ByteVector e2("YW55IGNhcm5hbCBwbGVhc3VyZQ=="); + ByteVector e3("YW55IGNhcm5hbCBwbGVhc3Vy"); + + // Encode + CPPUNIT_ASSERT_EQUAL(eempty, sempty.toBase64()); + CPPUNIT_ASSERT_EQUAL(e0, s0.toBase64()); + CPPUNIT_ASSERT_EQUAL(e1, s1.toBase64()); + CPPUNIT_ASSERT_EQUAL(e2, s2.toBase64()); + CPPUNIT_ASSERT_EQUAL(e3, s3.toBase64()); + + // Decode + CPPUNIT_ASSERT_EQUAL(sempty, ByteVector::fromBase64(eempty)); + CPPUNIT_ASSERT_EQUAL(s0, ByteVector::fromBase64(e0)); + CPPUNIT_ASSERT_EQUAL(s1, ByteVector::fromBase64(e1)); + CPPUNIT_ASSERT_EQUAL(s2, ByteVector::fromBase64(e2)); + CPPUNIT_ASSERT_EQUAL(s3, ByteVector::fromBase64(e3)); + + CPPUNIT_ASSERT_EQUAL(t0, ByteVector::fromBase64(s0.toBase64())); + CPPUNIT_ASSERT_EQUAL(t1, ByteVector::fromBase64(s1.toBase64())); + CPPUNIT_ASSERT_EQUAL(t2, ByteVector::fromBase64(s2.toBase64())); + CPPUNIT_ASSERT_EQUAL(t3, ByteVector::fromBase64(s3.toBase64())); + + ByteVector all((size_t)256, '\0'); + + // in order + { + for (int i = 0; i < 256; i++) { + all[i] = (unsigned char)i; + } + ByteVector b64 = all.toBase64(); + ByteVector original = ByteVector::fromBase64(b64); + CPPUNIT_ASSERT_EQUAL(all, original); + } + + // reverse + { + for (int i = 0; i < 256; i++) { + all[i] = (unsigned char)255 - i; + } + ByteVector b64 = all.toBase64(); + ByteVector original = ByteVector::fromBase64(b64); + CPPUNIT_ASSERT_EQUAL(all, original); + } + + // all zeroes + { + for (int i = 0; i < 256; i++) { + all[i] = 0; + } + ByteVector b64 = all.toBase64(); + ByteVector original = ByteVector::fromBase64(b64); + CPPUNIT_ASSERT_EQUAL(all, original); + } + + // all ones + { + for (int i = 0; i < 256; i++) { + all[i] = (unsigned char)0xff; + } + ByteVector b64 = all.toBase64(); + ByteVector original = ByteVector::fromBase64(b64); + CPPUNIT_ASSERT_EQUAL(all, original); + } + + // Missing end bytes + { + // No missing bytes + ByteVector m0("YW55IGNhcm5hbCBwbGVhc3VyZQ=="); + CPPUNIT_ASSERT_EQUAL(s2, ByteVector::fromBase64(m0)); + + // 1 missing byte + ByteVector m1("YW55IGNhcm5hbCBwbGVhc3VyZQ="); + CPPUNIT_ASSERT_EQUAL(sempty, ByteVector::fromBase64(m1)); + + // 2 missing bytes + ByteVector m2("YW55IGNhcm5hbCBwbGVhc3VyZQ"); + CPPUNIT_ASSERT_EQUAL(sempty, ByteVector::fromBase64(m2)); + + // 3 missing bytes + ByteVector m3("YW55IGNhcm5hbCBwbGVhc3VyZ"); + CPPUNIT_ASSERT_EQUAL(sempty, ByteVector::fromBase64(m3)); + } + + // Grok invalid characters + { + ByteVector invalid("abd\x00\x01\x02\x03\x04"); + CPPUNIT_ASSERT_EQUAL(sempty, ByteVector::fromBase64(invalid)); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector); diff --git a/tests/taglib/test_bytevectorlist.cpp b/tests/taglib/test_bytevectorlist.cpp new file mode 100644 index 000000000..75da4a6fc --- /dev/null +++ b/tests/taglib/test_bytevectorlist.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 "tbytevector.h" +#include "tbytevectorlist.h" +#include + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestByteVectorList : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestByteVectorList); + CPPUNIT_TEST(testSplitSingleChar); + CPPUNIT_TEST(testSplitSingleChar_2); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSplitSingleChar() { + ByteVector v("a b"); + + ByteVectorList l = ByteVectorList::split(v, " "); + CPPUNIT_ASSERT_EQUAL((size_t)2, l.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); + CPPUNIT_ASSERT_EQUAL(ByteVector("b"), l[1]); + } + + void testSplitSingleChar_2() { + ByteVector v("a"); + + ByteVectorList l = ByteVectorList::split(v, " "); + CPPUNIT_ASSERT_EQUAL((size_t)1, l.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorList); diff --git a/tests/taglib/test_bytevectorstream.cpp b/tests/taglib/test_bytevectorstream.cpp new file mode 100644 index 000000000..21b111fc9 --- /dev/null +++ b/tests/taglib/test_bytevectorstream.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + copyright : (C) 2011 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 "tbytevectorstream.h" +#include + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestByteVectorStream : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestByteVectorStream); + CPPUNIT_TEST(testInitialData); + CPPUNIT_TEST(testWriteBlock); + CPPUNIT_TEST(testWriteBlockResize); + CPPUNIT_TEST(testReadBlock); + CPPUNIT_TEST(testRemoveBlock); + CPPUNIT_TEST(testInsert); + CPPUNIT_TEST(testSeekEnd); + CPPUNIT_TEST_SUITE_END(); + + public: + void testInitialData() { + ByteVector v("abcd"); + ByteVectorStream stream(v); + + CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), *stream.data()); + } + + void testWriteBlock() { + ByteVector v("abcd"); + ByteVectorStream stream(v); + + stream.seek(1); + stream.writeBlock(ByteVector("xx")); + CPPUNIT_ASSERT_EQUAL(ByteVector("axxd"), *stream.data()); + } + + void testWriteBlockResize() { + ByteVector v("abcd"); + ByteVectorStream stream(v); + + stream.seek(3); + stream.writeBlock(ByteVector("xx")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcxx"), *stream.data()); + stream.seek(5); + stream.writeBlock(ByteVector("yy")); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcxxyy"), *stream.data()); + } + + void testReadBlock() { + ByteVector v("abcd"); + ByteVectorStream stream(v); + + CPPUNIT_ASSERT_EQUAL(ByteVector("a"), stream.readBlock(1)); + CPPUNIT_ASSERT_EQUAL(ByteVector("bc"), stream.readBlock(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("d"), stream.readBlock(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector(""), stream.readBlock(3)); + } + + void testRemoveBlock() { + ByteVector v("abcd"); + ByteVectorStream stream(v); + + stream.removeBlock(1, 1); + CPPUNIT_ASSERT_EQUAL(ByteVector("acd"), *stream.data()); + stream.removeBlock(0, 2); + CPPUNIT_ASSERT_EQUAL(ByteVector("d"), *stream.data()); + stream.removeBlock(0, 2); + CPPUNIT_ASSERT_EQUAL(ByteVector(""), *stream.data()); + } + + void testInsert() { + ByteVector v("abcd"); + ByteVectorStream stream(v); + + stream.insert(ByteVector("xx"), 1, 1); + CPPUNIT_ASSERT_EQUAL(ByteVector("axxcd"), *stream.data()); + stream.insert(ByteVector("yy"), 0, 2); + CPPUNIT_ASSERT_EQUAL(ByteVector("yyxcd"), *stream.data()); + stream.insert(ByteVector("foa"), 3, 2); + CPPUNIT_ASSERT_EQUAL(ByteVector("yyxfoa"), *stream.data()); + stream.insert(ByteVector("123"), 3, 0); + CPPUNIT_ASSERT_EQUAL(ByteVector("yyx123foa"), *stream.data()); + } + + void testSeekEnd() { + ByteVector v("abcdefghijklmnopqrstuvwxyz"); + ByteVectorStream stream(v); + CPPUNIT_ASSERT_EQUAL(26LL, stream.length()); + + stream.seek(-4, IOStream::End); + CPPUNIT_ASSERT_EQUAL(ByteVector("w"), stream.readBlock(1)); + + stream.seek(-25, IOStream::End); + CPPUNIT_ASSERT_EQUAL(ByteVector("b"), stream.readBlock(1)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorStream); diff --git a/tests/taglib/test_dsdiff.cpp b/tests/taglib/test_dsdiff.cpp new file mode 100644 index 000000000..86a439114 --- /dev/null +++ b/tests/taglib/test_dsdiff.cpp @@ -0,0 +1,108 @@ +#include +#include +#include + +#include "tag.h" +#include "tbytevectorlist.h" +#include "dsdifffile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestDSDIFF : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestDSDIFF); + CPPUNIT_TEST(testProperties); + CPPUNIT_TEST(testTags); + CPPUNIT_TEST(testSaveID3v2); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST_SUITE_END(); + + public: + void testProperties() { + DSDIFF::File f(TEST_FILE_PATH_C("empty10ms.dff")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(10, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(5644, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(2822400, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL((long long)28224, f.audioProperties()->sampleCount()); + } + + void testTags() { + ScopedFileCopy copy("empty10ms", ".dff"); + string newname = copy.fileName(); + + DSDIFF::File *f = new DSDIFF::File(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String(""), f->tag()->artist()); + f->tag()->setArtist("The Artist"); + f->save(); + delete f; + + f = new DSDIFF::File(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); + delete f; + } + + void testSaveID3v2() { + ScopedFileCopy copy("empty10ms", ".dff"); + string newname = copy.fileName(); + + { + DSDIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + + f.tag()->setTitle(L"TitleXXX"); + f.save(); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + } + { + DSDIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String(L"TitleXXX"), f.tag()->title()); + + f.tag()->setTitle(""); + f.save(); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + { + DSDIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + f.tag()->setTitle(L"TitleXXX"); + f.save(); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + } + { + DSDIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String(L"TitleXXX"), f.tag()->title()); + } + } + + void testRepeatedSave() { + ScopedFileCopy copy("empty10ms", ".dff"); + string newname = copy.fileName(); + + { + DSDIFF::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String(""), f.tag()->title()); + f.tag()->setTitle("NEW TITLE"); + f.save(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE"), f.tag()->title()); + f.tag()->setTitle("NEW TITLE 2"); + f.save(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), f.tag()->title()); + CPPUNIT_ASSERT_EQUAL(8252LL, f.length()); + f.save(); + CPPUNIT_ASSERT_EQUAL(8252LL, f.length()); + } + { + DSDIFF::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), f.tag()->title()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestDSDIFF); diff --git a/tests/taglib/test_dsf.cpp b/tests/taglib/test_dsf.cpp new file mode 100644 index 000000000..7e73f7a53 --- /dev/null +++ b/tests/taglib/test_dsf.cpp @@ -0,0 +1,68 @@ +#include +#include +#include + +#include "tag.h" +#include "tbytevectorlist.h" +#include "dsffile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestDSF : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestDSF); + CPPUNIT_TEST(testBasic1); + CPPUNIT_TEST(testBasic2); + CPPUNIT_TEST(testTags); + CPPUNIT_TEST_SUITE_END(); + + public: + void testBasic1() { + DSF::File f(TEST_FILE_PATH_C("empty.dsf")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(2822, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(2822400, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->formatVersion()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->formatID()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channelType()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL((long long)0, f.audioProperties()->sampleCount()); + } + + void testBasic2() { + DSF::File f(TEST_FILE_PATH_C("empty10ms.dsf")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(10, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(5645, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(2822400, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->formatVersion()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->formatID()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channelType()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL((long long)28224, f.audioProperties()->sampleCount()); + CPPUNIT_ASSERT_EQUAL(4096, f.audioProperties()->blockSizePerChannel()); + } + + void testTags() { + ScopedFileCopy copy("empty10ms", ".dsf"); + string newname = copy.fileName(); + + DSF::File *f = new DSF::File(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String(""), f->tag()->artist()); + f->tag()->setArtist("The Artist"); + f->save(); + delete f; + + f = new DSF::File(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); + delete f; + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestDSF); diff --git a/tests/taglib/test_file.cpp b/tests/taglib/test_file.cpp new file mode 100644 index 000000000..6a370e873 --- /dev/null +++ b/tests/taglib/test_file.cpp @@ -0,0 +1,147 @@ +/*************************************************************************** + 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 "tfile.h" +#include "utils.h" + +using namespace Strawberry_TagLib::TagLib; + +// File subclass that gives tests access to filesystem operations +class PlainFile : public File { + public: + explicit PlainFile(FileName name) : File(name) {} + Tag *tag() const override { return nullptr; } + AudioProperties *audioProperties() const override { return nullptr; } + bool save() override { return false; } + void truncate(long length) { File::truncate(length); } +}; + +class TestFile : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestFile); + CPPUNIT_TEST(testFindInSmallFile); + CPPUNIT_TEST(testRFindInSmallFile); + CPPUNIT_TEST(testSeek); + CPPUNIT_TEST(testTruncate); + CPPUNIT_TEST_SUITE_END(); + + public: + void testFindInSmallFile() { + ScopedFileCopy copy("empty", ".ogg"); + std::string name = copy.fileName(); + { + PlainFile file(name.c_str()); + file.seek(0); + file.writeBlock(ByteVector("0123456239", 10)); + file.truncate(10); + } + { + PlainFile file(name.c_str()); + CPPUNIT_ASSERT_EQUAL(10LL, file.length()); + + CPPUNIT_ASSERT_EQUAL(2LL, file.find(ByteVector("23", 2))); + CPPUNIT_ASSERT_EQUAL(2LL, file.find(ByteVector("23", 2), 2)); + CPPUNIT_ASSERT_EQUAL(7LL, file.find(ByteVector("23", 2), 3)); + + file.seek(0); + const ByteVector v = file.readBlock(static_cast(file.length())); + CPPUNIT_ASSERT_EQUAL((size_t)10, v.size()); + + CPPUNIT_ASSERT_EQUAL((long long)v.find("23"), file.find("23")); + CPPUNIT_ASSERT_EQUAL((long long)v.find("23", 2), file.find("23", 2)); + CPPUNIT_ASSERT_EQUAL((long long)v.find("23", 3), file.find("23", 3)); + } + } + + void testRFindInSmallFile() { + ScopedFileCopy copy("empty", ".ogg"); + std::string name = copy.fileName(); + { + PlainFile file(name.c_str()); + file.seek(0); + file.writeBlock(ByteVector("0123456239", 10)); + file.truncate(10); + } + { + PlainFile file(name.c_str()); + CPPUNIT_ASSERT_EQUAL(10LL, file.length()); + + CPPUNIT_ASSERT_EQUAL(7LL, file.rfind(ByteVector("23", 2))); + CPPUNIT_ASSERT_EQUAL(7LL, file.rfind(ByteVector("23", 2), 7)); + CPPUNIT_ASSERT_EQUAL(2LL, file.rfind(ByteVector("23", 2), 6)); + + file.seek(0); + const ByteVector v = file.readBlock(static_cast(file.length())); + CPPUNIT_ASSERT_EQUAL((size_t)10, v.size()); + + CPPUNIT_ASSERT_EQUAL((long long)v.rfind("23"), file.rfind("23")); + CPPUNIT_ASSERT_EQUAL((long long)v.rfind("23", 7), file.rfind("23", 7)); + CPPUNIT_ASSERT_EQUAL((long long)v.rfind("23", 6), file.rfind("23", 6)); + } + } + + void testSeek() { + ScopedFileCopy copy("empty", ".ogg"); + std::string name = copy.fileName(); + + PlainFile f(name.c_str()); + CPPUNIT_ASSERT_EQUAL(0LL, f.tell()); + CPPUNIT_ASSERT_EQUAL(4328LL, f.length()); + + f.seek(100, File::Beginning); + CPPUNIT_ASSERT_EQUAL(100LL, f.tell()); + f.seek(100, File::Current); + CPPUNIT_ASSERT_EQUAL(200LL, f.tell()); + f.seek(-300, File::Current); + CPPUNIT_ASSERT_EQUAL(200LL, f.tell()); + + f.seek(-100, File::End); + CPPUNIT_ASSERT_EQUAL(4228LL, f.tell()); + f.seek(-100, File::Current); + CPPUNIT_ASSERT_EQUAL(4128LL, f.tell()); + f.seek(300, File::Current); + CPPUNIT_ASSERT_EQUAL(4428LL, f.tell()); + } + + void testTruncate() { + ScopedFileCopy copy("empty", ".ogg"); + std::string name = copy.fileName(); + + { + PlainFile f(name.c_str()); + CPPUNIT_ASSERT_EQUAL(4328LL, f.length()); + + f.truncate(2000); + CPPUNIT_ASSERT_EQUAL(2000LL, f.length()); + } + { + PlainFile f(name.c_str()); + CPPUNIT_ASSERT_EQUAL(2000LL, f.length()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestFile); diff --git a/tests/taglib/test_fileref.cpp b/tests/taglib/test_fileref.cpp new file mode 100644 index 000000000..f224686ef --- /dev/null +++ b/tests/taglib/test_fileref.cpp @@ -0,0 +1,305 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "fileref.h" +#include "oggflacfile.h" +#include "vorbisfile.h" +#include "mpegfile.h" +#include "mpcfile.h" +#include "asffile.h" +#include "speexfile.h" +#include "flacfile.h" +#include "trueaudiofile.h" +#include "mp4file.h" +#include "wavfile.h" +#include "apefile.h" +#include "aifffile.h" +#include "dsffile.h" +#include "dsdifffile.h" +#include "tfilestream.h" +#include "tbytevectorstream.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +namespace { +class DummyResolver : public FileRef::FileTypeResolver { + public: + File *createFile(FileName fileName, bool, AudioProperties::ReadStyle) const override { + return new Ogg::Vorbis::File(fileName); + } +}; +} // namespace + +class TestFileRef : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestFileRef); + CPPUNIT_TEST(testASF); + CPPUNIT_TEST(testMusepack); + CPPUNIT_TEST(testVorbis); + CPPUNIT_TEST(testSpeex); + CPPUNIT_TEST(testFLAC); + CPPUNIT_TEST(testMP3); + CPPUNIT_TEST(testOGA_FLAC); + CPPUNIT_TEST(testOGA_Vorbis); + CPPUNIT_TEST(testMP4_1); + CPPUNIT_TEST(testMP4_2); + CPPUNIT_TEST(testMP4_3); + CPPUNIT_TEST(testMP4_4); + CPPUNIT_TEST(testTrueAudio); + CPPUNIT_TEST(testAPE); + CPPUNIT_TEST(testWav); + CPPUNIT_TEST(testAIFF_1); + CPPUNIT_TEST(testAIFF_2); + CPPUNIT_TEST(testDSF); + CPPUNIT_TEST(testDSDIFF); + CPPUNIT_TEST(testUnsupported); + CPPUNIT_TEST(testFileResolver); + CPPUNIT_TEST_SUITE_END(); + + public: + template + void fileRefSave(const string &filename, const string &ext) { + ScopedFileCopy copy(filename, ext); + string newname = copy.fileName(); + + { + FileRef f(newname.c_str()); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + f.tag()->setArtist("test artist"); + f.tag()->setTitle("test title"); + f.tag()->setGenre("Test!"); + f.tag()->setAlbum("albummmm"); + f.tag()->setTrack(5); + f.tag()->setYear(2020); + f.save(); + } + { + FileRef f(newname.c_str()); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("test artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); + f.tag()->setArtist("ttest artist"); + f.tag()->setTitle("ytest title"); + f.tag()->setGenre("uTest!"); + f.tag()->setAlbum("ialbummmm"); + f.tag()->setTrack(7); + f.tag()->setYear(2080); + f.save(); + } + { + FileRef f(newname.c_str()); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("ttest artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); + } + + { + FileStream fs(newname.c_str()); + FileRef f(&fs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("ttest artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); + f.tag()->setArtist("test artist"); + f.tag()->setTitle("test title"); + f.tag()->setGenre("Test!"); + f.tag()->setAlbum("albummmm"); + f.tag()->setTrack(5); + f.tag()->setYear(2020); + f.save(); + } + + ByteVector fileContent; + { + FileStream fs(newname.c_str()); + FileRef f(&fs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("test artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); + + fs.seek(0); + fileContent = fs.readBlock(fs.length()); + } + + { + ByteVectorStream bs(fileContent); + FileRef f(&bs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("test artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); + f.tag()->setArtist("ttest artist"); + f.tag()->setTitle("ytest title"); + f.tag()->setGenre("uTest!"); + f.tag()->setAlbum("ialbummmm"); + f.tag()->setTrack(7); + f.tag()->setYear(2080); + f.save(); + + fileContent = *bs.data(); + } + { + ByteVectorStream bs(fileContent); + FileRef f(&bs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("ttest artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); + } + } + + void testMusepack() { + fileRefSave("click", ".mpc"); + } + + void testASF() { + fileRefSave("silence-1", ".wma"); + } + + void testVorbis() { + fileRefSave("empty", ".ogg"); + } + + void testSpeex() { + fileRefSave("empty", ".spx"); + } + + void testFLAC() { + fileRefSave("no-tags", ".flac"); + } + + void testMP3() { + fileRefSave("xing", ".mp3"); + } + + void testTrueAudio() { + fileRefSave("empty", ".tta"); + } + + void testMP4_1() { + fileRefSave("has-tags", ".m4a"); + } + + void testMP4_2() { + fileRefSave("no-tags", ".m4a"); + } + + void testMP4_3() { + fileRefSave("no-tags", ".3g2"); + } + + void testMP4_4() { + fileRefSave("blank_video", ".m4v"); + } + + void testWav() { + fileRefSave("empty", ".wav"); + } + + void testOGA_FLAC() { + fileRefSave("empty_flac", ".oga"); + } + + void testOGA_Vorbis() { + fileRefSave("empty_vorbis", ".oga"); + } + + void testAPE() { + fileRefSave("mac-399", ".ape"); + } + + void testAIFF_1() { + fileRefSave("empty", ".aiff"); + } + + void testAIFF_2() { + fileRefSave("alaw", ".aifc"); + } + + void testDSF() { + fileRefSave("empty10ms", ".dsf"); + } + + void testDSDIFF() { + fileRefSave("empty10ms", ".dff"); + } + + void testUnsupported() { + FileRef f1(TEST_FILE_PATH_C("no-extension")); + CPPUNIT_ASSERT(f1.isNull()); + + FileRef f2(TEST_FILE_PATH_C("unsupported-extension.xx")); + CPPUNIT_ASSERT(f2.isNull()); + } + + void testFileResolver() { + { + FileRef f(TEST_FILE_PATH_C("xing.mp3")); + CPPUNIT_ASSERT(dynamic_cast(f.file()) != nullptr); + } + + DummyResolver resolver; + FileRef::addFileTypeResolver(&resolver); + + { + FileRef f(TEST_FILE_PATH_C("xing.mp3")); + CPPUNIT_ASSERT(dynamic_cast(f.file()) != nullptr); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestFileRef); diff --git a/tests/taglib/test_flac.cpp b/tests/taglib/test_flac.cpp new file mode 100644 index 000000000..0e10eb095 --- /dev/null +++ b/tests/taglib/test_flac.cpp @@ -0,0 +1,514 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "flacfile.h" +#include "xiphcomment.h" +#include "id3v1tag.h" +#include "id3v2tag.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestFLAC : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestFLAC); + CPPUNIT_TEST(testSignature); + CPPUNIT_TEST(testMultipleCommentBlocks); + CPPUNIT_TEST(testReadPicture); + CPPUNIT_TEST(testAddPicture); + CPPUNIT_TEST(testReplacePicture); + CPPUNIT_TEST(testRemoveAllPictures); + CPPUNIT_TEST(testRepeatedSave1); + CPPUNIT_TEST(testRepeatedSave2); + CPPUNIT_TEST(testRepeatedSave3); + CPPUNIT_TEST(testSaveMultipleValues); + CPPUNIT_TEST(testDict); + CPPUNIT_TEST(testInvalid); + CPPUNIT_TEST(testAudioProperties); + CPPUNIT_TEST(testZeroSizedPadding1); + CPPUNIT_TEST(testZeroSizedPadding2); + CPPUNIT_TEST(testShrinkPadding); + CPPUNIT_TEST(testSaveID3v1); + CPPUNIT_TEST(testUpdateID3v2); + CPPUNIT_TEST(testEmptyID3v2); + CPPUNIT_TEST(testStripTags); + CPPUNIT_TEST(testRemoveXiphField); + CPPUNIT_TEST(testEmptySeekTable); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSignature() { + FLAC::File f(TEST_FILE_PATH_C("no-tags.flac")); + CPPUNIT_ASSERT_EQUAL(ByteVector("a1b141f766e9849ac3db1030a20a3c77"), f.audioProperties()->signature().toHex()); + } + + void testMultipleCommentBlocks() { + ScopedFileCopy copy("multiple-vc", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("Artist 1"), f.tag()->artist()); + f.tag()->setArtist("The Artist"); + f.save(); + } + { + FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("The Artist"), f.tag()->artist()); + CPPUNIT_ASSERT_EQUAL(69LL, f.find("Artist")); + CPPUNIT_ASSERT_EQUAL(-1LL, f.find("Artist", 70)); + } + } + + void testReadPicture() { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + + FLAC::Picture *pic = lst.front(); + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(1, pic->width()); + CPPUNIT_ASSERT_EQUAL(1, pic->height()); + CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); + CPPUNIT_ASSERT_EQUAL((size_t)150, pic->data().size()); + } + + void testAddPicture() { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + + FLAC::Picture *newpic = new FLAC::Picture(); + newpic->setType(FLAC::Picture::BackCover); + newpic->setWidth(5); + newpic->setHeight(6); + newpic->setColorDepth(16); + newpic->setNumColors(7); + newpic->setMimeType("image/jpeg"); + newpic->setDescription("new image"); + newpic->setData("JPEG data"); + f.addPicture(newpic); + f.save(); + } + { + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)2, lst.size()); + + FLAC::Picture *pic = lst[0]; + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(1, pic->width()); + CPPUNIT_ASSERT_EQUAL(1, pic->height()); + CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); + CPPUNIT_ASSERT_EQUAL((size_t)150, pic->data().size()); + + pic = lst[1]; + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(5, pic->width()); + CPPUNIT_ASSERT_EQUAL(6, pic->height()); + CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); + } + } + + void testReplacePicture() { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + + FLAC::Picture *newpic = new FLAC::Picture(); + newpic->setType(FLAC::Picture::BackCover); + newpic->setWidth(5); + newpic->setHeight(6); + newpic->setColorDepth(16); + newpic->setNumColors(7); + newpic->setMimeType("image/jpeg"); + newpic->setDescription("new image"); + newpic->setData("JPEG data"); + f.removePictures(); + f.addPicture(newpic); + f.save(); + } + { + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + + FLAC::Picture *pic = lst[0]; + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(5, pic->width()); + CPPUNIT_ASSERT_EQUAL(6, pic->height()); + CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); + } + } + + void testRemoveAllPictures() { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + + f.removePictures(); + f.save(); + } + { + FLAC::File f(newname.c_str()); + List lst = f.pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)0, lst.size()); + } + } + + void testRepeatedSave1() { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("Silence"), f.tag()->title()); + f.tag()->setTitle("NEW TITLE"); + f.save(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE"), f.tag()->title()); + f.tag()->setTitle("NEW TITLE 2"); + f.save(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), f.tag()->title()); + } + { + FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), f.tag()->title()); + } + } + + void testRepeatedSave2() { + ScopedFileCopy copy("no-tags", ".flac"); + + FLAC::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle("0123456789"); + f.save(); + CPPUNIT_ASSERT_EQUAL(5735LL, f.length()); + f.save(); + CPPUNIT_ASSERT_EQUAL(5735LL, f.length()); + CPPUNIT_ASSERT(f.find("fLaC") >= 0); + } + + void testRepeatedSave3() { + ScopedFileCopy copy("no-tags", ".flac"); + + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->setTitle(longText(8 * 1024)); + f.save(); + CPPUNIT_ASSERT_EQUAL(12862LL, f.length()); + f.save(); + CPPUNIT_ASSERT_EQUAL(12862LL, f.length()); + } + + void testSaveMultipleValues() { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + f.xiphComment(true)->addField("ARTIST", "artist 1", true); + f.xiphComment(true)->addField("ARTIST", "artist 2", false); + f.save(); + } + { + FLAC::File f(newname.c_str()); + Ogg::FieldListMap m = f.xiphComment()->fieldListMap(); + CPPUNIT_ASSERT_EQUAL((size_t)2, m["ARTIST"].size()); + CPPUNIT_ASSERT_EQUAL(String("artist 1"), m["ARTIST"][0]); + CPPUNIT_ASSERT_EQUAL(String("artist 2"), m["ARTIST"][1]); + } + } + + void testDict() { + // test unicode & multiple values with dict interface + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + { + FLAC::File f(newname.c_str()); + PropertyMap dict; + dict["ARTIST"].append("artøst 1"); + dict["ARTIST"].append("artöst 2"); + f.setProperties(dict); + f.save(); + } + { + FLAC::File f(newname.c_str()); + PropertyMap dict = f.properties(); + CPPUNIT_ASSERT_EQUAL((size_t)2, dict["ARTIST"].size()); + CPPUNIT_ASSERT_EQUAL(String("artøst 1"), dict["ARTIST"][0]); + CPPUNIT_ASSERT_EQUAL(String("artöst 2"), dict["ARTIST"][1]); + } + } + + void testInvalid() { + ScopedFileCopy copy("silence-44-s", ".flac"); + PropertyMap map; + map[L"H\x00c4\x00d6"] = String("bla"); + FLAC::File f(copy.fileName().c_str()); + PropertyMap invalid = f.setProperties(map); + CPPUNIT_ASSERT_EQUAL((size_t)1, invalid.size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, f.properties().size()); + } + + void testAudioProperties() { + FLAC::File f(TEST_FILE_PATH_C("sinewave.flac")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3550, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(145, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(156556ULL, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL( + ByteVector("\xcf\xe3\xd9\xda\xba\xde\xab\x2c\xbf\x2c\xa2\x35\x27\x4b\x7f\x76"), + f.audioProperties()->signature()); + } + + void testZeroSizedPadding1() { + ScopedFileCopy copy("zero-sized-padding", ".flac"); + + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + } + + void testZeroSizedPadding2() { + ScopedFileCopy copy("silence-44-s", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->setTitle("ABC"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->setTitle(std::string(3067, 'X').c_str()); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + } + } + + void testShrinkPadding() { + ScopedFileCopy copy("no-tags", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->setTitle(longText(128 * 1024)); + f.save(); + CPPUNIT_ASSERT(f.length() > 128 * 1024); + } + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->setTitle("0123456789"); + f.save(); + CPPUNIT_ASSERT(f.length() < 8 * 1024); + } + } + + void testSaveID3v1() { + ScopedFileCopy copy("no-tags", ".flac"); + + ByteVector audioStream; + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + CPPUNIT_ASSERT_EQUAL(4692LL, f.length()); + + f.seek(0x0100); + audioStream = f.readBlock(4436); + + f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.save(); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + CPPUNIT_ASSERT_EQUAL(4820LL, f.length()); + + f.seek(0x0100); + CPPUNIT_ASSERT_EQUAL(audioStream, f.readBlock(4436)); + } + } + + void testUpdateID3v2() { + ScopedFileCopy copy("no-tags", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle("0123456789"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + f.ID3v2Tag()->setTitle("ABCDEFGHIJ"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("ABCDEFGHIJ"), f.ID3v2Tag()->title()); + } + } + + void testEmptyID3v2() { + ScopedFileCopy copy("no-tags", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.ID3v2Tag(true); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + } + + void testStripTags() { + ScopedFileCopy copy("silence-44-s", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment(true)->setTitle("XiphComment Title"); + f.ID3v1Tag(true)->setTitle("ID3v1 Title"); + f.ID3v2Tag(true)->setTitle("ID3v2 Title"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasXiphComment()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String("XiphComment Title"), f.xiphComment()->title()); + CPPUNIT_ASSERT_EQUAL(String("ID3v1 Title"), f.ID3v1Tag()->title()); + CPPUNIT_ASSERT_EQUAL(String("ID3v2 Title"), f.ID3v2Tag()->title()); + f.strip(FLAC::File::ID3v2); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasXiphComment()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String("XiphComment Title"), f.xiphComment()->title()); + CPPUNIT_ASSERT_EQUAL(String("ID3v1 Title"), f.ID3v1Tag()->title()); + f.strip(FLAC::File::ID3v1); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasXiphComment()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String("XiphComment Title"), f.xiphComment()->title()); + f.strip(FLAC::File::XiphComment); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasXiphComment()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + CPPUNIT_ASSERT(f.xiphComment()->isEmpty()); + CPPUNIT_ASSERT_EQUAL(String("reference libFLAC 1.1.0 20030126"), f.xiphComment()->vendorID()); + } + } + + void testRemoveXiphField() { + ScopedFileCopy copy("silence-44-s", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment(true)->setTitle("XiphComment Title"); + f.ID3v2Tag(true)->setTitle("ID3v2 Title"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("XiphComment Title"), f.xiphComment()->title()); + f.xiphComment()->removeFields("TITLE"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String(), f.xiphComment()->title()); + } + } + + void testEmptySeekTable() { + ScopedFileCopy copy("empty-seektable", ".flac"); + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + f.xiphComment(true)->setTitle("XiphComment Title"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + f.seek(42); + const ByteVector data = f.readBlock(4); + CPPUNIT_ASSERT_EQUAL(ByteVector("\x03\x00\x00\x00", 4), data); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC); diff --git a/tests/taglib/test_flacpicture.cpp b/tests/taglib/test_flacpicture.cpp new file mode 100644 index 000000000..4efbb1019 --- /dev/null +++ b/tests/taglib/test_flacpicture.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + copyright : (C) 2010 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "flacfile.h" +#include "flacmetadatablock.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestFLACPicture : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestFLACPicture); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testPassThrough); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; + const char *pdata = reinterpret_cast(data); + + FLAC::Picture pic(ByteVector(pdata, 199)); + + CPPUNIT_ASSERT_EQUAL(3, int(pic.type())); + CPPUNIT_ASSERT_EQUAL(1, pic.width()); + CPPUNIT_ASSERT_EQUAL(1, pic.height()); + CPPUNIT_ASSERT_EQUAL(24, pic.colorDepth()); + CPPUNIT_ASSERT_EQUAL(0, pic.numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/png"), pic.mimeType()); + CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic.description()); + CPPUNIT_ASSERT_EQUAL((size_t)150, pic.data().size()); + } + + void testPassThrough() { + const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; + const char *pdata = reinterpret_cast(data); + + FLAC::Picture pic(ByteVector(pdata, 199)); + CPPUNIT_ASSERT_EQUAL(ByteVector(pdata, 199), pic.render()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACPicture); diff --git a/tests/taglib/test_flacunknownmetadatablock.cpp b/tests/taglib/test_flacunknownmetadatablock.cpp new file mode 100644 index 000000000..85e146e8d --- /dev/null +++ b/tests/taglib/test_flacunknownmetadatablock.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + copyright : (C) 2012 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "flacunknownmetadatablock.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestFLACUnknownMetadataBlock : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestFLACUnknownMetadataBlock); + CPPUNIT_TEST(testAccessors); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAccessors() { + ByteVector data("abc\x01", 4); + FLAC::UnknownMetadataBlock block(42, data); + CPPUNIT_ASSERT_EQUAL(42, block.code()); + CPPUNIT_ASSERT_EQUAL(data, block.data()); + CPPUNIT_ASSERT_EQUAL(data, block.render()); + ByteVector data2("xxx", 3); + block.setCode(13); + block.setData(data2); + CPPUNIT_ASSERT_EQUAL(13, block.code()); + CPPUNIT_ASSERT_EQUAL(data2, block.data()); + CPPUNIT_ASSERT_EQUAL(data2, block.render()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACUnknownMetadataBlock); diff --git a/tests/taglib/test_id3v1.cpp b/tests/taglib/test_id3v1.cpp new file mode 100644 index 000000000..b90c67fdf --- /dev/null +++ b/tests/taglib/test_id3v1.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tstring.h" +#include "mpegfile.h" +#include "id3v1tag.h" +#include "id3v1genres.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestID3v1 : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestID3v1); + CPPUNIT_TEST(testStripWhiteSpace); + CPPUNIT_TEST(testGenres); + CPPUNIT_TEST_SUITE_END(); + + public: + void testStripWhiteSpace() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + { + MPEG::File f(newname.c_str()); + f.ID3v1Tag(true)->setArtist("Artist "); + f.save(); + } + + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT(f.ID3v1Tag(false)); + CPPUNIT_ASSERT_EQUAL(String("Artist"), f.ID3v1Tag(false)->artist()); + } + } + + void testGenres() { + CPPUNIT_ASSERT_EQUAL(String("Darkwave"), ID3v1::genre(50)); + CPPUNIT_ASSERT_EQUAL(100, ID3v1::genreIndex("Humour")); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v1); diff --git a/tests/taglib/test_id3v2.cpp b/tests/taglib/test_id3v2.cpp new file mode 100644 index 000000000..dd6836733 --- /dev/null +++ b/tests/taglib/test_id3v2.cpp @@ -0,0 +1,1285 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "id3v2tag.h" +#include "mpegfile.h" +#include "id3v2frame.h" +#include "uniquefileidentifierframe.h" +#include "textidentificationframe.h" +#include "attachedpictureframe.h" +#include "unsynchronizedlyricsframe.h" +#include "synchronizedlyricsframe.h" +#include "eventtimingcodesframe.h" +#include "generalencapsulatedobjectframe.h" +#include "relativevolumeframe.h" +#include "popularimeterframe.h" +#include "urllinkframe.h" +#include "ownershipframe.h" +#include "unknownframe.h" +#include "chapterframe.h" +#include "tableofcontentsframe.h" +#include "tdebug.h" +#include "tpropertymap.h" +#include "tzlib.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class PublicFrame : public ID3v2::Frame { + public: + PublicFrame() : ID3v2::Frame(ByteVector("XXXX\0\0\0\0\0\0", 10)) {} + String readStringField(const ByteVector &data, String::Type encoding) { + size_t position = 0; + return ID3v2::Frame::readStringField(data, encoding, position); + } + String toString() const override { return String(); } + void parseFields(const ByteVector &) override {} + ByteVector renderFields() const override { return ByteVector(); } +}; + +class TestID3v2 : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestID3v2); + CPPUNIT_TEST(testUnsynchDecode); + CPPUNIT_TEST(testDowngradeUTF8ForID3v23_1); + CPPUNIT_TEST(testDowngradeUTF8ForID3v23_2); + CPPUNIT_TEST(testUTF16BEDelimiter); + CPPUNIT_TEST(testUTF16Delimiter); + CPPUNIT_TEST(testReadStringField); + CPPUNIT_TEST(testParseAPIC); + CPPUNIT_TEST(testParseAPIC_UTF16_BOM); + CPPUNIT_TEST(testParseAPICv22); + CPPUNIT_TEST(testDontRender22); + CPPUNIT_TEST(testParseGEOB); + CPPUNIT_TEST(testPOPMtoString); + CPPUNIT_TEST(testParsePOPM); + CPPUNIT_TEST(testParsePOPMWithoutCounter); + CPPUNIT_TEST(testRenderPOPM); + CPPUNIT_TEST(testPOPMFromFile); + CPPUNIT_TEST(testParseRelativeVolumeFrame); + CPPUNIT_TEST(testParseUniqueFileIdentifierFrame); + CPPUNIT_TEST(testParseEmptyUniqueFileIdentifierFrame); + CPPUNIT_TEST(testBrokenFrame1); + CPPUNIT_TEST(testItunes24FrameSize); + CPPUNIT_TEST(testParseUrlLinkFrame); + CPPUNIT_TEST(testRenderUrlLinkFrame); + CPPUNIT_TEST(testParseUserUrlLinkFrame); + CPPUNIT_TEST(testRenderUserUrlLinkFrame); + CPPUNIT_TEST(testParseOwnershipFrame); + CPPUNIT_TEST(testRenderOwnershipFrame); + CPPUNIT_TEST(testParseSynchronizedLyricsFrame); + CPPUNIT_TEST(testParseSynchronizedLyricsFrameWithEmptyDescritpion); + CPPUNIT_TEST(testRenderSynchronizedLyricsFrame); + CPPUNIT_TEST(testParseEventTimingCodesFrame); + CPPUNIT_TEST(testRenderEventTimingCodesFrame); + CPPUNIT_TEST(testSaveUTF16Comment); + CPPUNIT_TEST(testUpdateGenre23_1); + CPPUNIT_TEST(testUpdateGenre23_2); + CPPUNIT_TEST(testUpdateGenre24); + CPPUNIT_TEST(testUpdateDate22); + CPPUNIT_TEST(testDowngradeTo23); + // CPPUNIT_TEST(testUpdateFullDate22); TODO TYE+TDA should be upgraded to TDRC together + CPPUNIT_TEST(testCompressedFrameWithBrokenLength); + CPPUNIT_TEST(testW000); + CPPUNIT_TEST(testPropertyInterface); + CPPUNIT_TEST(testPropertyInterface2); + CPPUNIT_TEST(testPropertiesMovement); + CPPUNIT_TEST(testPropertyGrouping); + CPPUNIT_TEST(testDeleteFrame); + CPPUNIT_TEST(testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2); + CPPUNIT_TEST(testParseChapterFrame); + CPPUNIT_TEST(testRenderChapterFrame); + CPPUNIT_TEST(testParseTableOfContentsFrame); + CPPUNIT_TEST(testRenderTableOfContentsFrame); + CPPUNIT_TEST(testShrinkPadding); + CPPUNIT_TEST(testEmptyFrame); + CPPUNIT_TEST(testDuplicateTags); + CPPUNIT_TEST(testParseTOCFrameWithManyChildren); + CPPUNIT_TEST_SUITE_END(); + + public: + void testUnsynchDecode() { + MPEG::File f(TEST_FILE_PATH_C("unsynch.id3"), false); + CPPUNIT_ASSERT(f.tag()); + CPPUNIT_ASSERT_EQUAL(String("My babe just cares for me"), f.tag()->title()); + } + + void testDowngradeUTF8ForID3v23_1() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + ID3v2::TextIdentificationFrame *f = new ID3v2::TextIdentificationFrame(ByteVector("TPE1"), String::UTF8); + StringList sl; + sl.append("Foo"); + f->setText(sl); + + MPEG::File file(newname.c_str()); + file.ID3v2Tag(true)->addFrame(f); + file.save(MPEG::File::ID3v2, File::StripOthers, ID3v2::v3); + CPPUNIT_ASSERT_EQUAL(true, file.hasID3v2Tag()); + + ByteVector data = f->render(); + CPPUNIT_ASSERT_EQUAL((size_t)(4 + 4 + 2 + 1 + 6 + 2), data.size()); + + ID3v2::TextIdentificationFrame f2(data); + CPPUNIT_ASSERT_EQUAL(sl, f2.fieldList()); + CPPUNIT_ASSERT_EQUAL(String::UTF16, f2.textEncoding()); + } + + void testDowngradeUTF8ForID3v23_2() { + ScopedFileCopy copy("xing", ".mp3"); + + ID3v2::UnsynchronizedLyricsFrame *f = new ID3v2::UnsynchronizedLyricsFrame(String::UTF8); + f->setText("Foo"); + + MPEG::File file(copy.fileName().c_str()); + file.ID3v2Tag(true)->addFrame(f); + file.save(MPEG::File::ID3v2, File::StripOthers, ID3v2::v3); + CPPUNIT_ASSERT(file.hasID3v2Tag()); + + ByteVector data = f->render(); + CPPUNIT_ASSERT_EQUAL(static_cast(4 + 4 + 2 + 1 + 3 + 2 + 2 + 6 + 2), data.size()); + + ID3v2::UnsynchronizedLyricsFrame f2(data); + CPPUNIT_ASSERT_EQUAL(String("Foo"), f2.text()); + CPPUNIT_ASSERT_EQUAL(String::UTF16, f2.textEncoding()); + } + + void testUTF16BEDelimiter() { + ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF16BE); + StringList sl; + sl.append("Foo"); + sl.append("Bar"); + f.setText(sl); + CPPUNIT_ASSERT_EQUAL(static_cast(4 + 4 + 2 + 1 + 6 + 2 + 6), f.render().size()); + } + + void testUTF16Delimiter() { + ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF16); + StringList sl; + sl.append("Foo"); + sl.append("Bar"); + f.setText(sl); + CPPUNIT_ASSERT_EQUAL(static_cast(4 + 4 + 2 + 1 + 8 + 2 + 8), f.render().size()); + } + + void testBrokenFrame1() { + MPEG::File f(TEST_FILE_PATH_C("broken-tenc.id3"), false); + CPPUNIT_ASSERT(f.tag()); + CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TENC")); + } + + void testReadStringField() { + PublicFrame f; + ByteVector data("abc\0", 4); + String str = f.readStringField(data, String::Latin1); + CPPUNIT_ASSERT_EQUAL(String("abc"), str); + } + + // http://bugs.kde.org/show_bug.cgi?id=151078 + void testParseAPIC() { + std::cout << __PRETTY_FUNCTION__ << "\n"; + ID3v2::AttachedPictureFrame f(ByteVector("APIC" + "\x00\x00\x00\x07" + "\x00\x00" + "\x00" + "m\x00" + "\x01" + "d\x00" + "\x00", + 17)); + std::cout << __PRETTY_FUNCTION__ << "\n"; + CPPUNIT_ASSERT_EQUAL(String("m"), f.mimeType()); + CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, f.type()); + CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); + } + + void testParseAPIC_UTF16_BOM() { + ID3v2::AttachedPictureFrame f(ByteVector( + "\x41\x50\x49\x43\x00\x02\x0c\x59\x00\x00\x01\x69\x6d\x61\x67\x65" + "\x2f\x6a\x70\x65\x67\x00\x00\xfe\xff\x00\x63\x00\x6f\x00\x76\x00" + "\x65\x00\x72\x00\x2e\x00\x6a\x00\x70\x00\x67\x00\x00\xff\xd8\xff", + 16 * 3)); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), f.mimeType()); + CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, f.type()); + CPPUNIT_ASSERT_EQUAL(String("cover.jpg"), f.description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\xd8\xff", 3), f.picture()); + } + + void testParseAPICv22() { + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ByteVector data = ByteVector("PIC" + "\x00\x00\x08" + "\x00" + "JPG" + "\x01" + "d\x00" + "\x00", + 14); + ID3v2::Header header; + header.setMajorVersion(2); + ID3v2::AttachedPictureFrame *frame = dynamic_cast(factory->createFrame(data, &header)); + + CPPUNIT_ASSERT(frame); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), frame->mimeType()); + CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, frame->type()); + CPPUNIT_ASSERT_EQUAL(String("d"), frame->description()); + + delete frame; + } + + void testDontRender22() { + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ByteVector data = ByteVector("FOO" + "\x00\x00\x08" + "\x00" + "JPG" + "\x01" + "d\x00" + "\x00", + 14); + ID3v2::Header header; + header.setMajorVersion(2); + ID3v2::UnknownFrame *frame = + dynamic_cast(factory->createFrame(data, &header)); + + CPPUNIT_ASSERT(frame); + + ID3v2::Tag tag; + tag.addFrame(frame); + CPPUNIT_ASSERT_EQUAL((size_t)1034, tag.render().size()); + } + + // http://bugs.kde.org/show_bug.cgi?id=151078 + void testParseGEOB() { + ID3v2::GeneralEncapsulatedObjectFrame f(ByteVector("GEOB" + "\x00\x00\x00\x08" + "\x00\x00" + "\x00" + "m\x00" + "f\x00" + "d\x00" + "\x00", + 18)); + CPPUNIT_ASSERT_EQUAL(String("m"), f.mimeType()); + CPPUNIT_ASSERT_EQUAL(String("f"), f.fileName()); + CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); + } + + void testParsePOPM() { + ID3v2::PopularimeterFrame f(ByteVector("POPM" + "\x00\x00\x00\x17" + "\x00\x00" + "email@example.com\x00" + "\x02" + "\x00\x00\x00\x03", + 33)); + CPPUNIT_ASSERT_EQUAL(String("email@example.com"), f.email()); + CPPUNIT_ASSERT_EQUAL(2, f.rating()); + CPPUNIT_ASSERT_EQUAL((unsigned int)3, f.counter()); + } + + void testParsePOPMWithoutCounter() { + ID3v2::PopularimeterFrame f(ByteVector("POPM" + "\x00\x00\x00\x13" + "\x00\x00" + "email@example.com\x00" + "\x02", + 29)); + CPPUNIT_ASSERT_EQUAL(String("email@example.com"), f.email()); + CPPUNIT_ASSERT_EQUAL(2, f.rating()); + CPPUNIT_ASSERT_EQUAL((unsigned int)0, f.counter()); + } + + void testRenderPOPM() { + ID3v2::PopularimeterFrame f; + f.setEmail("email@example.com"); + f.setRating(2); + f.setCounter(3); + CPPUNIT_ASSERT_EQUAL( + ByteVector("POPM" + "\x00\x00\x00\x17" + "\x00\x00" + "email@example.com\x00" + "\x02" + "\x00\x00\x00\x03", + 33), + f.render()); + } + + void testPOPMtoString() { + ID3v2::PopularimeterFrame f; + f.setEmail("email@example.com"); + f.setRating(2); + f.setCounter(3); + CPPUNIT_ASSERT_EQUAL( + String("email@example.com rating=2 counter=3"), f.toString()); + } + + void testPOPMFromFile() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + ID3v2::PopularimeterFrame *f = new ID3v2::PopularimeterFrame(); + f->setEmail("email@example.com"); + f->setRating(200); + f->setCounter(3); + + { + MPEG::File foo(newname.c_str()); + foo.ID3v2Tag()->addFrame(f); + foo.save(); + } + { + MPEG::File bar(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("email@example.com"), dynamic_cast(bar.ID3v2Tag()->frameList("POPM").front())->email()); + CPPUNIT_ASSERT_EQUAL(200, dynamic_cast(bar.ID3v2Tag()->frameList("POPM").front())->rating()); + } + } + + // http://bugs.kde.org/show_bug.cgi?id=150481 + void testParseRelativeVolumeFrame() { + ID3v2::RelativeVolumeFrame f( + ByteVector("RVA2" // Frame ID + "\x00\x00\x00\x0B" // Frame size + "\x00\x00" // Frame flags + "ident\x00" // Identification + "\x02" // Type of channel + "\x00\x0F" // Volume adjustment + "\x08" // Bits representing peak + "\x45", + 21)); // Peak volume + CPPUNIT_ASSERT_EQUAL(String("ident"), f.identification()); + CPPUNIT_ASSERT_EQUAL(15.0f / 512.0f, + f.volumeAdjustment(ID3v2::RelativeVolumeFrame::FrontRight)); + CPPUNIT_ASSERT_EQUAL((unsigned char)8, + f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).bitsRepresentingPeak); + CPPUNIT_ASSERT_EQUAL(ByteVector("\x45"), + f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).peakVolume); + } + + void testParseUniqueFileIdentifierFrame() { + ID3v2::UniqueFileIdentifierFrame f( + ByteVector("UFID" // Frame ID + "\x00\x00\x00\x09" // Frame size + "\x00\x00" // Frame flags + "owner\x00" // Owner identifier + "\x00\x01\x02", + 19)); // Identifier + CPPUNIT_ASSERT_EQUAL(String("owner"), + f.owner()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\x00\x01\x02", 3), + f.identifier()); + } + + void testParseEmptyUniqueFileIdentifierFrame() { + ID3v2::UniqueFileIdentifierFrame f( + ByteVector("UFID" // Frame ID + "\x00\x00\x00\x01" // Frame size + "\x00\x00" // Frame flags + "\x00" // Owner identifier + "", + 11)); // Identifier + CPPUNIT_ASSERT_EQUAL(String(), + f.owner()); + CPPUNIT_ASSERT_EQUAL(ByteVector(), + f.identifier()); + } + + void testParseUrlLinkFrame() { + ID3v2::UrlLinkFrame f( + ByteVector("WOAF" // Frame ID + "\x00\x00\x00\x12" // Frame size + "\x00\x00" // Frame flags + "http://example.com", + 28)); // URL + CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); + } + + void testRenderUrlLinkFrame() { + ID3v2::UrlLinkFrame f("WOAF"); + f.setUrl("http://example.com"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("WOAF" // Frame ID + "\x00\x00\x00\x12" // Frame size + "\x00\x00" // Frame flags + "http://example.com", + 28), // URL + f.render()); + } + + void testParseUserUrlLinkFrame() { + ID3v2::UserUrlLinkFrame f( + ByteVector("WXXX" // Frame ID + "\x00\x00\x00\x17" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "foo\x00" // Description + "http://example.com", + 33)); // URL + CPPUNIT_ASSERT_EQUAL(String("foo"), f.description()); + CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); + } + + void testRenderUserUrlLinkFrame() { + ID3v2::UserUrlLinkFrame f; + f.setDescription("foo"); + f.setUrl("http://example.com"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("WXXX" // Frame ID + "\x00\x00\x00\x17" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "foo\x00" // Description + "http://example.com", + 33), // URL + f.render()); + } + + void testParseOwnershipFrame() { + ID3v2::OwnershipFrame f( + ByteVector("OWNE" // Frame ID + "\x00\x00\x00\x19" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "GBP1.99\x00" // Price paid + "20120905" // Date of purchase + "Beatport", + 35)); // Seller + CPPUNIT_ASSERT_EQUAL(String("GBP1.99"), f.pricePaid()); + CPPUNIT_ASSERT_EQUAL(String("20120905"), f.datePurchased()); + CPPUNIT_ASSERT_EQUAL(String("Beatport"), f.seller()); + } + + void testRenderOwnershipFrame() { + ID3v2::OwnershipFrame f; + f.setPricePaid("GBP1.99"); + f.setDatePurchased("20120905"); + f.setSeller("Beatport"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("OWNE" // Frame ID + "\x00\x00\x00\x19" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "GBP1.99\x00" // Price paid + "20120905" // Date of purchase + "Beatport", + 35), // URL + f.render()); + } + + void testParseSynchronizedLyricsFrame() { + ID3v2::SynchronizedLyricsFrame f( + ByteVector("SYLT" // Frame ID + "\x00\x00\x00\x21" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "eng" // Language + "\x02" // Time stamp format + "\x01" // Content type + "foo\x00" // Content descriptor + "Example\x00" // 1st text + "\x00\x00\x04\xd2" // 1st time stamp + "Lyrics\x00" // 2nd text + "\x00\x00\x11\xd7", + 43)); // 2nd time stamp + CPPUNIT_ASSERT_EQUAL(String::Latin1, f.textEncoding()); + CPPUNIT_ASSERT_EQUAL(ByteVector("eng", 3), f.language()); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchronizedLyricsFrame::AbsoluteMilliseconds, + f.timestampFormat()); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchronizedLyricsFrame::Lyrics, f.type()); + CPPUNIT_ASSERT_EQUAL(String("foo"), f.description()); + ID3v2::SynchronizedLyricsFrame::SynchedTextList stl = f.synchedText(); + CPPUNIT_ASSERT_EQUAL(static_cast(2), stl.size()); + CPPUNIT_ASSERT_EQUAL(String("Example"), stl[0].text); + CPPUNIT_ASSERT_EQUAL((unsigned int)1234, stl[0].time); + CPPUNIT_ASSERT_EQUAL(String("Lyrics"), stl[1].text); + CPPUNIT_ASSERT_EQUAL((unsigned int)4567, stl[1].time); + } + + void testParseSynchronizedLyricsFrameWithEmptyDescritpion() { + ID3v2::SynchronizedLyricsFrame f( + ByteVector("SYLT" // Frame ID + "\x00\x00\x00\x21" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "eng" // Language + "\x02" // Time stamp format + "\x01" // Content type + "\x00" // Content descriptor + "Example\x00" // 1st text + "\x00\x00\x04\xd2" // 1st time stamp + "Lyrics\x00" // 2nd text + "\x00\x00\x11\xd7", + 40)); // 2nd time stamp + CPPUNIT_ASSERT_EQUAL(String::Latin1, f.textEncoding()); + CPPUNIT_ASSERT_EQUAL(ByteVector("eng", 3), f.language()); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchronizedLyricsFrame::AbsoluteMilliseconds, + f.timestampFormat()); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchronizedLyricsFrame::Lyrics, f.type()); + CPPUNIT_ASSERT(f.description().isEmpty()); + ID3v2::SynchronizedLyricsFrame::SynchedTextList stl = f.synchedText(); + CPPUNIT_ASSERT_EQUAL(static_cast(2), stl.size()); + CPPUNIT_ASSERT_EQUAL(String("Example"), stl[0].text); + CPPUNIT_ASSERT_EQUAL((unsigned int)1234, stl[0].time); + CPPUNIT_ASSERT_EQUAL(String("Lyrics"), stl[1].text); + CPPUNIT_ASSERT_EQUAL((unsigned int)4567, stl[1].time); + } + + void testRenderSynchronizedLyricsFrame() { + ID3v2::SynchronizedLyricsFrame f; + f.setTextEncoding(String::Latin1); + f.setLanguage(ByteVector("eng", 3)); + f.setTimestampFormat(ID3v2::SynchronizedLyricsFrame::AbsoluteMilliseconds); + f.setType(ID3v2::SynchronizedLyricsFrame::Lyrics); + f.setDescription("foo"); + ID3v2::SynchronizedLyricsFrame::SynchedTextList stl; + stl.append(ID3v2::SynchronizedLyricsFrame::SynchedText(1234, "Example")); + stl.append(ID3v2::SynchronizedLyricsFrame::SynchedText(4567, "Lyrics")); + f.setSynchedText(stl); + CPPUNIT_ASSERT_EQUAL( + ByteVector("SYLT" // Frame ID + "\x00\x00\x00\x21" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "eng" // Language + "\x02" // Time stamp format + "\x01" // Content type + "foo\x00" // Content descriptor + "Example\x00" // 1st text + "\x00\x00\x04\xd2" // 1st time stamp + "Lyrics\x00" // 2nd text + "\x00\x00\x11\xd7", + 43), // 2nd time stamp + f.render()); + } + + void testParseEventTimingCodesFrame() { + ID3v2::EventTimingCodesFrame f( + ByteVector("ETCO" // Frame ID + "\x00\x00\x00\x0b" // Frame size + "\x00\x00" // Frame flags + "\x02" // Time stamp format + "\x02" // 1st event + "\x00\x00\xf3\x5c" // 1st time stamp + "\xfe" // 2nd event + "\x00\x36\xee\x80", + 21)); // 2nd time stamp + CPPUNIT_ASSERT_EQUAL(ID3v2::EventTimingCodesFrame::AbsoluteMilliseconds, + f.timestampFormat()); + ID3v2::EventTimingCodesFrame::SynchedEventList sel = f.synchedEvents(); + CPPUNIT_ASSERT_EQUAL(size_t(2), sel.size()); + CPPUNIT_ASSERT_EQUAL(ID3v2::EventTimingCodesFrame::IntroStart, sel[0].type); + CPPUNIT_ASSERT_EQUAL((unsigned int)62300, sel[0].time); + CPPUNIT_ASSERT_EQUAL(ID3v2::EventTimingCodesFrame::AudioFileEnds, sel[1].type); + CPPUNIT_ASSERT_EQUAL((unsigned int)3600000, sel[1].time); + } + + void testRenderEventTimingCodesFrame() { + ID3v2::EventTimingCodesFrame f; + f.setTimestampFormat(ID3v2::EventTimingCodesFrame::AbsoluteMilliseconds); + ID3v2::EventTimingCodesFrame::SynchedEventList sel; + sel.append(ID3v2::EventTimingCodesFrame::SynchedEvent(62300, ID3v2::EventTimingCodesFrame::IntroStart)); + sel.append(ID3v2::EventTimingCodesFrame::SynchedEvent(3600000, ID3v2::EventTimingCodesFrame::AudioFileEnds)); + f.setSynchedEvents(sel); + CPPUNIT_ASSERT_EQUAL( + ByteVector("ETCO" // Frame ID + "\x00\x00\x00\x0b" // Frame size + "\x00\x00" // Frame flags + "\x02" // Time stamp format + "\x02" // 1st event + "\x00\x00\xf3\x5c" // 1st time stamp + "\xfe" // 2nd event + "\x00\x36\xee\x80", + 21), // 2nd time stamp + f.render()); + } + + void testItunes24FrameSize() { + MPEG::File f(TEST_FILE_PATH_C("005411.id3"), false); + CPPUNIT_ASSERT(f.tag()); + CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("TIT2")); + CPPUNIT_ASSERT_EQUAL(String("Sunshine Superman"), f.ID3v2Tag()->frameListMap()["TIT2"].front()->toString()); + } + + void testSaveUTF16Comment() { + String::Type defaultEncoding = ID3v2::FrameFactory::instance()->defaultTextEncoding(); + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + ID3v2::FrameFactory::instance()->setDefaultTextEncoding(String::UTF16); + { + MPEG::File foo(newname.c_str()); + foo.strip(); + foo.tag()->setComment("Test comment!"); + foo.save(); + } + { + MPEG::File bar(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("Test comment!"), bar.tag()->comment()); + ID3v2::FrameFactory::instance()->setDefaultTextEncoding(defaultEncoding); + } + } + + void testUpdateGenre23_1() { + // "Refinement" is the same as the ID3v1 genre - duplicate + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ByteVector data = ByteVector("TCON" // Frame ID + "\x00\x00\x00\x10" // Frame size + "\x00\x00" // Frame flags + "\x00" // Encoding + "(22)Death Metal", + 26); // Text + ID3v2::Header header; + header.setMajorVersion(3); + ID3v2::TextIdentificationFrame *frame = + dynamic_cast(factory->createFrame(data, &header)); + CPPUNIT_ASSERT_EQUAL((size_t)1, frame->fieldList().size()); + CPPUNIT_ASSERT_EQUAL(String("Death Metal"), frame->fieldList()[0]); + + ID3v2::Tag tag; + tag.addFrame(frame); + CPPUNIT_ASSERT_EQUAL(String("Death Metal"), tag.genre()); + } + + void testUpdateGenre23_2() { + // "Refinement" is different from the ID3v1 genre + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ByteVector data = ByteVector("TCON" // Frame ID + "\x00\x00\x00\x13" // Frame size + "\x00\x00" // Frame flags + "\x00" // Encoding + "(4)Eurodisco", + 23); // Text + ID3v2::Header header; + header.setMajorVersion(3); + ID3v2::TextIdentificationFrame *frame = + dynamic_cast(factory->createFrame(data, &header)); + CPPUNIT_ASSERT_EQUAL((size_t)2, frame->fieldList().size()); + CPPUNIT_ASSERT_EQUAL(String("4"), frame->fieldList()[0]); + CPPUNIT_ASSERT_EQUAL(String("Eurodisco"), frame->fieldList()[1]); + + ID3v2::Tag tag; + tag.addFrame(frame); + CPPUNIT_ASSERT_EQUAL(String("Disco Eurodisco"), tag.genre()); + } + + void testUpdateGenre24() { + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ByteVector data = ByteVector("TCON" // Frame ID + "\x00\x00\x00\x0D" // Frame size + "\x00\x00" // Frame flags + "\0" // Encoding + "14\0Eurodisco", + 23); // Text + ID3v2::Header header; + ID3v2::TextIdentificationFrame *frame = + dynamic_cast(factory->createFrame(data, &header)); + CPPUNIT_ASSERT_EQUAL((size_t)2, frame->fieldList().size()); + CPPUNIT_ASSERT_EQUAL(String("14"), frame->fieldList()[0]); + CPPUNIT_ASSERT_EQUAL(String("Eurodisco"), frame->fieldList()[1]); + + ID3v2::Tag tag; + tag.addFrame(frame); + CPPUNIT_ASSERT_EQUAL(String("R&B Eurodisco"), tag.genre()); + } + + void testUpdateDate22() { + MPEG::File f(TEST_FILE_PATH_C("id3v22-tda.mp3"), false); + CPPUNIT_ASSERT(f.tag()); + CPPUNIT_ASSERT_EQUAL((unsigned int)2010, f.tag()->year()); + } + + void testUpdateFullDate22() { + MPEG::File f(TEST_FILE_PATH_C("id3v22-tda.mp3"), false); + CPPUNIT_ASSERT(f.tag()); + CPPUNIT_ASSERT_EQUAL(String("2010-04-03"), f.ID3v2Tag()->frameListMap()["TDRC"].front()->toString()); + } + + void testDowngradeTo23() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + ID3v2::TextIdentificationFrame *tf; + { + MPEG::File foo(newname.c_str()); + tf = new ID3v2::TextIdentificationFrame("TDOR", String::Latin1); + tf->setText("2011-03-16"); + foo.ID3v2Tag()->addFrame(tf); + tf = new ID3v2::TextIdentificationFrame("TDRC", String::Latin1); + tf->setText("2012-04-17T12:01"); + foo.ID3v2Tag()->addFrame(tf); + tf = new ID3v2::TextIdentificationFrame("TMCL", String::Latin1); + tf->setText(StringList().append("Guitar").append("Artist 1").append("Drums").append("Artist 2")); + foo.ID3v2Tag()->addFrame(tf); + tf = new ID3v2::TextIdentificationFrame("TIPL", String::Latin1); + tf->setText(StringList().append("Producer").append("Artist 3").append("Mastering").append("Artist 4")); + foo.ID3v2Tag()->addFrame(tf); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDRL", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDTG", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TMOO", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TPRO", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOA", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOT", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSST", String::Latin1)); + foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOP", String::Latin1)); + foo.save(MPEG::File::AllTags, File::StripOthers, ID3v2::v3); + } + { + MPEG::File bar(newname.c_str()); + tf = dynamic_cast(bar.ID3v2Tag()->frameList("TDOR").front()); + CPPUNIT_ASSERT(tf); + CPPUNIT_ASSERT_EQUAL((size_t)1, tf->fieldList().size()); + CPPUNIT_ASSERT_EQUAL(String("2011"), tf->fieldList().front()); + tf = dynamic_cast(bar.ID3v2Tag()->frameList("TDRC").front()); + CPPUNIT_ASSERT(tf); + CPPUNIT_ASSERT_EQUAL((size_t)1, tf->fieldList().size()); + CPPUNIT_ASSERT_EQUAL(String("2012-04-17T12:01"), tf->fieldList().front()); + tf = dynamic_cast(bar.ID3v2Tag()->frameList("TIPL").front()); + CPPUNIT_ASSERT(tf); + CPPUNIT_ASSERT_EQUAL((size_t)8, tf->fieldList().size()); + CPPUNIT_ASSERT_EQUAL(String("Guitar"), tf->fieldList()[0]); + CPPUNIT_ASSERT_EQUAL(String("Artist 1"), tf->fieldList()[1]); + CPPUNIT_ASSERT_EQUAL(String("Drums"), tf->fieldList()[2]); + CPPUNIT_ASSERT_EQUAL(String("Artist 2"), tf->fieldList()[3]); + CPPUNIT_ASSERT_EQUAL(String("Producer"), tf->fieldList()[4]); + CPPUNIT_ASSERT_EQUAL(String("Artist 3"), tf->fieldList()[5]); + CPPUNIT_ASSERT_EQUAL(String("Mastering"), tf->fieldList()[6]); + CPPUNIT_ASSERT_EQUAL(String("Artist 4"), tf->fieldList()[7]); + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDRL")); + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDTG")); + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TMOO")); + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TPRO")); +#ifdef NO_ITUNES_HACKS + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOA")); + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOT")); + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOP")); +#endif + CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSST")); + } + } + + void testCompressedFrameWithBrokenLength() { + MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false); + CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC")); + + if (zlib::isAvailable()) { + ID3v2::AttachedPictureFrame *frame = dynamic_cast(f.ID3v2Tag()->frameListMap()["APIC"].front()); + CPPUNIT_ASSERT(frame); + CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType()); + CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type()); + CPPUNIT_ASSERT_EQUAL(String(""), frame->description()); + CPPUNIT_ASSERT_EQUAL((size_t)86414, frame->picture().size()); + } + else { + // Skip the test if ZLIB is not installed. + // The message "Compressed frames are currently not supported." will be displayed. + + ID3v2::UnknownFrame *frame = dynamic_cast(f.ID3v2Tag()->frameListMap()["APIC"].front()); + CPPUNIT_ASSERT(frame); + } + } + + void testW000() { + MPEG::File f(TEST_FILE_PATH_C("w000.mp3"), false); + CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("W000")); + ID3v2::UrlLinkFrame *frame = + dynamic_cast(f.ID3v2Tag()->frameListMap()["W000"].front()); + CPPUNIT_ASSERT(frame); + CPPUNIT_ASSERT_EQUAL(String("lukas.lalinsky@example.com____"), frame->url()); + } + + void testPropertyInterface() { + ScopedFileCopy copy("rare_frames", ".mp3"); + string newname = copy.fileName(); + MPEG::File f(newname.c_str()); + PropertyMap dict = f.ID3v2Tag(false)->properties(); + CPPUNIT_ASSERT_EQUAL((size_t)6, dict.size()); + + CPPUNIT_ASSERT(dict.contains("USERTEXTDESCRIPTION1")); + CPPUNIT_ASSERT(dict.contains("QuodLibet::USERTEXTDESCRIPTION2")); + CPPUNIT_ASSERT_EQUAL((size_t)2, dict["USERTEXTDESCRIPTION1"].size()); + CPPUNIT_ASSERT_EQUAL((size_t)2, dict["QuodLibet::USERTEXTDESCRIPTION2"].size()); + CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION1"][0]); + CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION1"][1]); + CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["QuodLibet::USERTEXTDESCRIPTION2"][0]); + CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["QuodLibet::USERTEXTDESCRIPTION2"][1]); + + CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"].front()); + + CPPUNIT_ASSERT_EQUAL(String("http://a.user.url"), dict["URL:USERURL"].front()); + + CPPUNIT_ASSERT_EQUAL(String("http://a.user.url/with/empty/description"), dict["URL"].front()); + CPPUNIT_ASSERT_EQUAL(String("A COMMENT"), dict["COMMENT"].front()); + + CPPUNIT_ASSERT_EQUAL((size_t)1u, dict.unsupportedData().size()); + CPPUNIT_ASSERT_EQUAL(String("UFID/supermihi@web.de"), dict.unsupportedData().front()); + } + + void testPropertyInterface2() { + ID3v2::Tag tag; + ID3v2::UnsynchronizedLyricsFrame *frame1 = new ID3v2::UnsynchronizedLyricsFrame(); + frame1->setDescription("test"); + frame1->setText("la-la-la test"); + tag.addFrame(frame1); + + ID3v2::UnsynchronizedLyricsFrame *frame2 = new ID3v2::UnsynchronizedLyricsFrame(); + frame2->setDescription(""); + frame2->setText("la-la-la nodescription"); + tag.addFrame(frame2); + + ID3v2::AttachedPictureFrame *frame3 = new ID3v2::AttachedPictureFrame(); + frame3->setDescription("test picture"); + tag.addFrame(frame3); + + ID3v2::TextIdentificationFrame *frame4 = new ID3v2::TextIdentificationFrame("TIPL"); + frame4->setText("single value is invalid for TIPL"); + tag.addFrame(frame4); + + ID3v2::TextIdentificationFrame *frame5 = new ID3v2::TextIdentificationFrame("TMCL"); + StringList tmclData; + tmclData.append("VIOLIN"); + tmclData.append("a violinist"); + tmclData.append("PIANO"); + tmclData.append("a pianist"); + frame5->setText(tmclData); + tag.addFrame(frame5); + + ID3v2::UniqueFileIdentifierFrame *frame6 = new ID3v2::UniqueFileIdentifierFrame("http://musicbrainz.org", "152454b9-19ba-49f3-9fc9-8fc26545cf41"); + tag.addFrame(frame6); + + ID3v2::UniqueFileIdentifierFrame *frame7 = new ID3v2::UniqueFileIdentifierFrame("http://example.com", "123"); + tag.addFrame(frame7); + + ID3v2::UserTextIdentificationFrame *frame8 = new ID3v2::UserTextIdentificationFrame(); + frame8->setDescription("MusicBrainz Album Id"); + frame8->setText("95c454a5-d7e0-4d8f-9900-db04aca98ab3"); + tag.addFrame(frame8); + + PropertyMap properties = tag.properties(); + + CPPUNIT_ASSERT_EQUAL((size_t)3u, properties.unsupportedData().size()); + CPPUNIT_ASSERT(properties.unsupportedData().contains("TIPL")); + CPPUNIT_ASSERT(properties.unsupportedData().contains("APIC")); + CPPUNIT_ASSERT(properties.unsupportedData().contains("UFID/http://example.com")); + + CPPUNIT_ASSERT(properties.contains("PERFORMER:VIOLIN")); + CPPUNIT_ASSERT(properties.contains("PERFORMER:PIANO")); + CPPUNIT_ASSERT_EQUAL(String("a violinist"), properties["PERFORMER:VIOLIN"].front()); + CPPUNIT_ASSERT_EQUAL(String("a pianist"), properties["PERFORMER:PIANO"].front()); + + CPPUNIT_ASSERT(properties.contains("LYRICS")); + CPPUNIT_ASSERT(properties.contains("LYRICS:TEST")); + + CPPUNIT_ASSERT(properties.contains("MUSICBRAINZ_TRACKID")); + CPPUNIT_ASSERT_EQUAL(String("152454b9-19ba-49f3-9fc9-8fc26545cf41"), properties["MUSICBRAINZ_TRACKID"].front()); + + CPPUNIT_ASSERT(properties.contains("MUSICBRAINZ_ALBUMID")); + CPPUNIT_ASSERT_EQUAL(String("95c454a5-d7e0-4d8f-9900-db04aca98ab3"), properties["MUSICBRAINZ_ALBUMID"].front()); + + tag.removeUnsupportedProperties(properties.unsupportedData()); + CPPUNIT_ASSERT(tag.frameList("APIC").isEmpty()); + CPPUNIT_ASSERT(tag.frameList("TIPL").isEmpty()); + CPPUNIT_ASSERT_EQUAL((ID3v2::UniqueFileIdentifierFrame *)nullptr, ID3v2::UniqueFileIdentifierFrame::findByOwner(&tag, "http://example.com")); + CPPUNIT_ASSERT_EQUAL(frame6, ID3v2::UniqueFileIdentifierFrame::findByOwner(&tag, "http://musicbrainz.org")); + } + + void testPropertiesMovement() { + ID3v2::Tag tag; + ID3v2::TextIdentificationFrame *frameMvnm = new ID3v2::TextIdentificationFrame("MVNM"); + frameMvnm->setText("Movement Name"); + tag.addFrame(frameMvnm); + + ID3v2::TextIdentificationFrame *frameMvin = new ID3v2::TextIdentificationFrame("MVIN"); + frameMvin->setText("2/3"); + tag.addFrame(frameMvin); + + PropertyMap properties = tag.properties(); + CPPUNIT_ASSERT(properties.contains("MOVEMENTNAME")); + CPPUNIT_ASSERT(properties.contains("MOVEMENTNUMBER")); + CPPUNIT_ASSERT_EQUAL(String("Movement Name"), properties["MOVEMENTNAME"].front()); + CPPUNIT_ASSERT_EQUAL(String("2/3"), properties["MOVEMENTNUMBER"].front()); + + ByteVector frameDataMvnm("MVNM" + "\x00\x00\x00\x0e" + "\x00\x00" + "\x00" + "Movement Name", + 24); + CPPUNIT_ASSERT_EQUAL(frameDataMvnm, frameMvnm->render()); + ByteVector frameDataMvin("MVIN" + "\x00\x00\x00\x04" + "\x00\x00" + "\x00" + "2/3", + 14); + CPPUNIT_ASSERT_EQUAL(frameDataMvin, frameMvin->render()); + + ID3v2::Header header; + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ID3v2::TextIdentificationFrame *parsedFrameMvnm = + dynamic_cast(factory->createFrame(frameDataMvnm, &header)); + ID3v2::TextIdentificationFrame *parsedFrameMvin = + dynamic_cast(factory->createFrame(frameDataMvin, &header)); + CPPUNIT_ASSERT(parsedFrameMvnm); + CPPUNIT_ASSERT(parsedFrameMvin); + CPPUNIT_ASSERT_EQUAL(String("Movement Name"), parsedFrameMvnm->toString()); + CPPUNIT_ASSERT_EQUAL(String("2/3"), parsedFrameMvin->toString()); + + tag.addFrame(parsedFrameMvnm); + tag.addFrame(parsedFrameMvin); + } + + void testPropertyGrouping() + { + ID3v2::Tag tag; + ID3v2::TextIdentificationFrame *frameGrp1 = new ID3v2::TextIdentificationFrame("GRP1"); + frameGrp1->setText("Grouping"); + tag.addFrame(frameGrp1); + + PropertyMap properties = tag.properties(); + CPPUNIT_ASSERT(properties.contains("GROUPING")); + CPPUNIT_ASSERT_EQUAL(String("Grouping"), properties["GROUPING"].front()); + + ByteVector frameDataGrp1("GRP1" + "\x00\x00\x00\x09" + "\x00\x00" + "\x00" + "Grouping", 19); + CPPUNIT_ASSERT_EQUAL(frameDataGrp1, frameGrp1->render()); + + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ID3v2::Header header; + ID3v2::TextIdentificationFrame *parsedFrameGrp1 = + dynamic_cast( + factory->createFrame(frameDataGrp1, &header)); + CPPUNIT_ASSERT(parsedFrameGrp1); + CPPUNIT_ASSERT_EQUAL(String("Grouping"), parsedFrameGrp1->toString()); + + tag.addFrame(parsedFrameGrp1); + } + + void testDeleteFrame() { + ScopedFileCopy copy("rare_frames", ".mp3"); + string newname = copy.fileName(); + + { + MPEG::File f(newname.c_str()); + ID3v2::Tag *t = f.ID3v2Tag(); + ID3v2::Frame *frame = t->frameList("TCON")[0]; + CPPUNIT_ASSERT_EQUAL(static_cast(1), t->frameList("TCON").size()); + t->removeFrame(frame, true); + f.save(MPEG::File::ID3v2); + } + { + MPEG::File f2(newname.c_str()); + ID3v2::Tag *t = f2.ID3v2Tag(); + CPPUNIT_ASSERT(t->frameList("TCON").isEmpty()); + } + } + + void testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + { + MPEG::File foo(newname.c_str()); + foo.tag()->setArtist("Artist"); + foo.save(MPEG::File::ID3v1 | MPEG::File::ID3v2); + } + + { + MPEG::File bar(newname.c_str()); + bar.ID3v2Tag()->removeFrames("TPE1"); + // Should strip ID3v1 here and not add old values to ID3v2 again + bar.save(MPEG::File::ID3v2, File::StripOthers); + } + + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TPE1")); + } + + void testParseChapterFrame() { + ID3v2::Header header; + + ByteVector chapterData = + ByteVector("CHAP" // Frame ID + "\x00\x00\x00\x20" // Frame size + "\x00\x00" // Frame flags + "\x43\x00" // Element ID ("C") + "\x00\x00\x00\x03" // Start time + "\x00\x00\x00\x05" // End time + "\x00\x00\x00\x02" // Start offset + "\x00\x00\x00\x03", + 28); // End offset + ByteVector embeddedFrameData = + ByteVector("TIT2" // Embedded frame ID + "\x00\x00\x00\x04" // Embedded frame size + "\x00\x00" // Embedded frame flags + "\x00" // TIT2 frame text encoding + "CH1", + 14); // Chapter title + + ID3v2::ChapterFrame f1(&header, chapterData); + + CPPUNIT_ASSERT_EQUAL(ByteVector("C"), f1.elementID()); + CPPUNIT_ASSERT((unsigned int)0x03 == f1.startTime()); + CPPUNIT_ASSERT((unsigned int)0x05 == f1.endTime()); + CPPUNIT_ASSERT((unsigned int)0x02 == f1.startOffset()); + CPPUNIT_ASSERT((unsigned int)0x03 == f1.endOffset()); + CPPUNIT_ASSERT((unsigned int)0x00 == f1.embeddedFrameList().size()); + + ID3v2::ChapterFrame f2(&header, chapterData + embeddedFrameData); + + CPPUNIT_ASSERT_EQUAL(ByteVector("C"), f2.elementID()); + CPPUNIT_ASSERT((unsigned int)0x03 == f2.startTime()); + CPPUNIT_ASSERT((unsigned int)0x05 == f2.endTime()); + CPPUNIT_ASSERT((unsigned int)0x02 == f2.startOffset()); + CPPUNIT_ASSERT((unsigned int)0x03 == f2.endOffset()); + CPPUNIT_ASSERT((unsigned int)0x01 == f2.embeddedFrameList().size()); + CPPUNIT_ASSERT(f2.embeddedFrameList("TIT2").size() == 1); + CPPUNIT_ASSERT(f2.embeddedFrameList("TIT2")[0]->toString() == "CH1"); + } + + void testRenderChapterFrame() { + ID3v2::Header header; + ID3v2::ChapterFrame f1(&header, "CHAP"); + f1.setElementID(ByteVector("\x43\x00", 2)); + f1.setStartTime(3); + f1.setEndTime(5); + f1.setStartOffset(2); + f1.setEndOffset(3); + ID3v2::TextIdentificationFrame *eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("CH1"); + f1.addEmbeddedFrame(eF); + + ByteVector expected = + ByteVector("CHAP" // Frame ID + "\x00\x00\x00\x20" // Frame size + "\x00\x00" // Frame flags + "\x43\x00" // Element ID + "\x00\x00\x00\x03" // Start time + "\x00\x00\x00\x05" // End time + "\x00\x00\x00\x02" // Start offset + "\x00\x00\x00\x03" // End offset + "TIT2" // Embedded frame ID + "\x00\x00\x00\x04" // Embedded frame size + "\x00\x00" // Embedded frame flags + "\x00" // TIT2 frame text encoding + "CH1", + 42); // Chapter title + + CPPUNIT_ASSERT_EQUAL(expected, f1.render()); + + f1.setElementID("C"); + + CPPUNIT_ASSERT_EQUAL(expected, f1.render()); + + ID3v2::FrameList frames; + eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("CH1"); + frames.append(eF); + + ID3v2::ChapterFrame f2(ByteVector("\x43\x00", 2), 3, 5, 2, 3, frames); + CPPUNIT_ASSERT_EQUAL(expected, f2.render()); + + frames.clear(); + eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("CH1"); + frames.append(eF); + + ID3v2::ChapterFrame f3(ByteVector("C\x00", 2), 3, 5, 2, 3, frames); + CPPUNIT_ASSERT_EQUAL(expected, f3.render()); + + frames.clear(); + eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("CH1"); + frames.append(eF); + + ID3v2::ChapterFrame f4("C", 3, 5, 2, 3, frames); + CPPUNIT_ASSERT_EQUAL(expected, f4.render()); + + CPPUNIT_ASSERT(!f4.toString().isEmpty()); + + ID3v2::ChapterFrame f5("C", 3, 5, 2, 3); + eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("CH1"); + f5.addEmbeddedFrame(eF); + CPPUNIT_ASSERT_EQUAL(expected, f5.render()); + } + + void testParseTableOfContentsFrame() { + ID3v2::Header header; + ID3v2::TableOfContentsFrame f( + &header, + ByteVector("CTOC" // Frame ID + "\x00\x00\x00\x16" // Frame size + "\x00\x00" // Frame flags + "\x54\x00" // Element ID ("T") + "\x01" // CTOC flags + "\x02" // Entry count + "\x43\x00" // First entry ("C") + "\x44\x00" // Second entry ("D") + "TIT2" // Embedded frame ID + "\x00\x00\x00\x04" // Embedded frame size + "\x00\x00" // Embedded frame flags + "\x00" // TIT2 frame text encoding + "TC1", + 32)); // Table of contents title + CPPUNIT_ASSERT_EQUAL(ByteVector("T"), f.elementID()); + CPPUNIT_ASSERT(!f.isTopLevel()); + CPPUNIT_ASSERT(f.isOrdered()); + CPPUNIT_ASSERT((unsigned int)0x02 == f.entryCount()); + CPPUNIT_ASSERT_EQUAL(ByteVector("C"), f.childElements()[0]); + CPPUNIT_ASSERT_EQUAL(ByteVector("D"), f.childElements()[1]); + CPPUNIT_ASSERT((unsigned int)0x01 == f.embeddedFrameList().size()); + CPPUNIT_ASSERT(f.embeddedFrameList("TIT2").size() == 1); + CPPUNIT_ASSERT(f.embeddedFrameList("TIT2")[0]->toString() == "TC1"); + } + + void testRenderTableOfContentsFrame() { + ID3v2::Header header; + ID3v2::TableOfContentsFrame f(&header, "CTOC"); + f.setElementID(ByteVector("\x54\x00", 2)); + f.setIsTopLevel(false); + f.setIsOrdered(true); + f.addChildElement(ByteVector("\x43\x00", 2)); + f.addChildElement(ByteVector("\x44\x00", 2)); + ID3v2::TextIdentificationFrame *eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("TC1"); + f.addEmbeddedFrame(eF); + CPPUNIT_ASSERT_EQUAL( + ByteVector("CTOC" // Frame ID + "\x00\x00\x00\x16" // Frame size + "\x00\x00" // Frame flags + "\x54\x00" // Element ID + "\x01" // CTOC flags + "\x02" // Entry count + "\x43\x00" // First entry + "\x44\x00" // Second entry + "TIT2" // Embedded frame ID + "\x00\x00\x00\x04" // Embedded frame size + "\x00\x00" // Embedded frame flags + "\x00" // TIT2 frame text encoding + "TC1", + 32), // Table of contents title + f.render()); + } + + void testShrinkPadding() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + { + MPEG::File f(newname.c_str()); + f.ID3v2Tag()->setTitle(longText(64 * 1024)); + f.save(MPEG::File::ID3v2, File::StripOthers); + } + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(74789LL, f.length()); + f.ID3v2Tag()->setTitle("ABCDEFGHIJ"); + f.save(MPEG::File::ID3v2, File::StripOthers); + } + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(9263LL, f.length()); + } + } + + void testEmptyFrame() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + { + MPEG::File f(newname.c_str()); + ID3v2::Tag *tag = f.ID3v2Tag(true); + + ID3v2::UrlLinkFrame *frame1 = new ID3v2::UrlLinkFrame( + ByteVector("WOAF\x00\x00\x00\x01\x00\x00\x00", 11)); + tag->addFrame(frame1); + + ID3v2::TextIdentificationFrame *frame2 = new ID3v2::TextIdentificationFrame("TIT2"); + frame2->setText("Title"); + tag->addFrame(frame2); + + f.save(); + } + + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); + + ID3v2::Tag *tag = f.ID3v2Tag(); + CPPUNIT_ASSERT_EQUAL(String("Title"), tag->title()); + CPPUNIT_ASSERT_EQUAL(true, tag->frameListMap()["WOAF"].isEmpty()); + } + } + + void testDuplicateTags() { + ScopedFileCopy copy("duplicate_id3v2", ".mp3"); + + ByteVector audioStream; + { + MPEG::File f(copy.fileName().c_str()); + f.seek(f.ID3v2Tag()->header()->completeTagSize()); + audioStream = f.readBlock(2089); + + // duplicate_id3v2.mp3 has duplicate ID3v2 tags. + // Sample rate will be 32000 if we can't skip the second tag. + + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL((unsigned int)8049, f.ID3v2Tag()->header()->completeTagSize()); + + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + + f.ID3v2Tag()->setArtist("Artist A"); + f.save(MPEG::File::ID3v2, File::StripOthers); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(3594LL, f.length()); + CPPUNIT_ASSERT_EQUAL((unsigned int)1505, f.ID3v2Tag()->header()->completeTagSize()); + CPPUNIT_ASSERT_EQUAL(String("Artist A"), f.ID3v2Tag()->artist()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + + f.seek(f.ID3v2Tag()->header()->completeTagSize()); + CPPUNIT_ASSERT_EQUAL(f.readBlock(2089), audioStream); + } + } + + void testParseTOCFrameWithManyChildren() { + MPEG::File f(TEST_FILE_PATH_C("toc_many_children.mp3")); + CPPUNIT_ASSERT(f.isValid()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2); diff --git a/tests/taglib/test_info.cpp b/tests/taglib/test_info.cpp new file mode 100644 index 000000000..46404803d --- /dev/null +++ b/tests/taglib/test_info.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + copyright : (C) 2012 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 +#include + +#include "infotag.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestInfoTag : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestInfoTag); + CPPUNIT_TEST(testTitle); + CPPUNIT_TEST(testNumericFields); + CPPUNIT_TEST_SUITE_END(); + + public: + void testTitle() { + RIFF::Info::Tag tag; + + CPPUNIT_ASSERT_EQUAL(String(""), tag.title()); + tag.setTitle("Test title 1"); + tag.setFieldText("TEST", "Dummy Text"); + + CPPUNIT_ASSERT_EQUAL(String("Test title 1"), tag.title()); + + RIFF::Info::FieldMap map = tag.fieldMap(); + CPPUNIT_ASSERT_EQUAL(String("Test title 1"), map["INAM"]); + CPPUNIT_ASSERT_EQUAL(String("Dummy Text"), map["TEST"]); + } + + void testNumericFields() { + RIFF::Info::Tag tag; + + CPPUNIT_ASSERT_EQUAL((unsigned int)0, tag.track()); + tag.setTrack(1234); + CPPUNIT_ASSERT_EQUAL((unsigned int)1234, tag.track()); + CPPUNIT_ASSERT_EQUAL(String("1234"), tag.fieldText("IPRT")); + + CPPUNIT_ASSERT_EQUAL((unsigned int)0, tag.year()); + tag.setYear(1234); + CPPUNIT_ASSERT_EQUAL((unsigned int)1234, tag.year()); + CPPUNIT_ASSERT_EQUAL(String("1234"), tag.fieldText("ICRD")); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestInfoTag); diff --git a/tests/taglib/test_it.cpp b/tests/taglib/test_it.cpp new file mode 100644 index 000000000..0268cd93f --- /dev/null +++ b/tests/taglib/test_it.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + 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 * + * 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 "itfile.h" +#include "tstringlist.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +static const String titleBefore("test song name"); +static const String titleAfter("changed title"); + +static const String commentBefore( + "This is a sample name.\n" + "In module file formats\n" + "sample names are abused\n" + "as multiline comments.\n" + " "); + +static const String newComment( + "This is a sample name!\n" + "In module file formats\n" + "sample names are abused\n" + "as multiline comments.\n" + "-----------------------------------\n" + "The previous line is truncated but starting with this line\n" + "the comment is not limeted in the line length but to 8000\n" + "additional characters (bytes).\n" + "\n" + "This is because it is saved in the 'message' proportion of\n" + "IT files."); + +static const String commentAfter( + "This is a sample name!\n" + "In module file formats\n" + "sample names are abused\n" + "as multiline comments.\n" + "-------------------------\n" + "The previous line is truncated but starting with this line\n" + "the comment is not limeted in the line length but to 8000\n" + "additional characters (bytes).\n" + "\n" + "This is because it is saved in the 'message' proportion of\n" + "IT files."); + +class TestIT : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestIT); + CPPUNIT_TEST(testReadTags); + CPPUNIT_TEST(testWriteTags); + CPPUNIT_TEST_SUITE_END(); + + public: + void testReadTags() { + testRead(TEST_FILE_PATH_C("test.it"), titleBefore, commentBefore); + } + + void testWriteTags() { + ScopedFileCopy copy("test", ".it"); + { + IT::File file(copy.fileName().c_str()); + CPPUNIT_ASSERT(file.tag() != nullptr); + file.tag()->setTitle(titleAfter); + file.tag()->setComment(newComment); + file.tag()->setTrackerName("won't be saved"); + CPPUNIT_ASSERT(file.save()); + } + testRead(copy.fileName().c_str(), titleAfter, commentAfter); + } + + private: + void testRead(FileName fileName, const String &title, const String &comment) { + IT::File file(fileName); + + CPPUNIT_ASSERT(file.isValid()); + + IT::AudioProperties *p = file.audioProperties(); + Mod::Tag *t = file.tag(); + + CPPUNIT_ASSERT(nullptr != p); + CPPUNIT_ASSERT(nullptr != t); + + CPPUNIT_ASSERT_EQUAL(0, p->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); + CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); + CPPUNIT_ASSERT_EQUAL(64, p->channels()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->lengthInPatterns()); + CPPUNIT_ASSERT_EQUAL(true, p->stereo()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->instrumentCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)5, p->sampleCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->patternCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)535, p->version()); + CPPUNIT_ASSERT_EQUAL((unsigned short)532, p->compatibleVersion()); + CPPUNIT_ASSERT_EQUAL((unsigned short)9, p->flags()); + CPPUNIT_ASSERT_EQUAL((unsigned char)128, p->globalVolume()); + CPPUNIT_ASSERT_EQUAL((unsigned char)48, p->mixVolume()); + CPPUNIT_ASSERT_EQUAL((unsigned char)125, p->tempo()); + CPPUNIT_ASSERT_EQUAL((unsigned char)6, p->bpmSpeed()); + CPPUNIT_ASSERT_EQUAL((unsigned char)128, p->panningSeparation()); + CPPUNIT_ASSERT_EQUAL((unsigned char)0, p->pitchWheelDepth()); + CPPUNIT_ASSERT_EQUAL(title, t->title()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); + CPPUNIT_ASSERT_EQUAL(comment, t->comment()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); + CPPUNIT_ASSERT_EQUAL(0U, t->year()); + CPPUNIT_ASSERT_EQUAL(0U, t->track()); + CPPUNIT_ASSERT_EQUAL(String("Impulse Tracker"), t->trackerName()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestIT); diff --git a/tests/taglib/test_list.cpp b/tests/taglib/test_list.cpp new file mode 100644 index 000000000..bb7ad20df --- /dev/null +++ b/tests/taglib/test_list.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 "tlist.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestList : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestList); + CPPUNIT_TEST(testAppend); + CPPUNIT_TEST(testDetach); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAppend() { + List l1; + List l2; + List l3; + l1.append(2); + l2.append(3); + l2.append(4); + l1.append(l2); + l1.prepend(1); + l3.append(1); + l3.append(2); + l3.append(3); + l3.append(4); + CPPUNIT_ASSERT_EQUAL((size_t)4, l1.size()); + CPPUNIT_ASSERT(l1 == l3); + } + + void testDetach() { + List l1; + l1.append(1); + l1.append(2); + l1.append(3); + l1.append(4); + + List l2 = l1; + List::Iterator it = l2.find(3); + *it = 33; + CPPUNIT_ASSERT_EQUAL(3, l1[2]); + CPPUNIT_ASSERT_EQUAL(33, l2[2]); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestList); diff --git a/tests/taglib/test_map.cpp b/tests/taglib/test_map.cpp new file mode 100644 index 000000000..5a58be7c6 --- /dev/null +++ b/tests/taglib/test_map.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 "tstring.h" +#include "tmap.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestMap : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMap); + CPPUNIT_TEST(testInsert); + CPPUNIT_TEST(testDetach); + CPPUNIT_TEST_SUITE_END(); + + public: + void testInsert() { + Map m1; + m1.insert("foo", 3); + m1.insert("bar", 5); + CPPUNIT_ASSERT_EQUAL((size_t)2, m1.size()); + CPPUNIT_ASSERT_EQUAL(3, m1["foo"]); + CPPUNIT_ASSERT_EQUAL(5, m1["bar"]); + m1.insert("foo", 7); + CPPUNIT_ASSERT_EQUAL((size_t)2, m1.size()); + CPPUNIT_ASSERT_EQUAL(7, m1["foo"]); + CPPUNIT_ASSERT_EQUAL(5, m1["bar"]); + } + + void testDetach() { + Map m1; + m1.insert("alice", 5); + m1.insert("bob", 9); + m1.insert("carol", 11); + + Map m2 = m1; + Map::Iterator it = m2.find("bob"); + (*it).second = 99; + CPPUNIT_ASSERT_EQUAL(9, m1["bob"]); + CPPUNIT_ASSERT_EQUAL(99, m2["bob"]); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMap); diff --git a/tests/taglib/test_mod.cpp b/tests/taglib/test_mod.cpp new file mode 100644 index 000000000..22bf08599 --- /dev/null +++ b/tests/taglib/test_mod.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + 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 * + * 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 "modfile.h" +#include "tpropertymap.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +static const String titleBefore("title of song"); +static const String titleAfter("changed title"); + +static const String commentBefore( + "Instrument names\n" + "are abused as\n" + "comments in\n" + "module file formats.\n" + "-+-+-+-+-+-+-+-+-+-+-+\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + +static const String newComment( + "This line will be truncated because it is too long for a mod instrument name.\n" + "This line is ok."); + +static const String commentAfter( + "This line will be trun\n" + "This line is ok.\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + +class TestMod : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMod); + CPPUNIT_TEST(testReadTags); + CPPUNIT_TEST(testWriteTags); + CPPUNIT_TEST(testPropertyInterface); + CPPUNIT_TEST_SUITE_END(); + + public: + void testReadTags() { + testRead(TEST_FILE_PATH_C("test.mod"), titleBefore, commentBefore); + } + + void testWriteTags() { + ScopedFileCopy copy("test", ".mod"); + { + Mod::File file(copy.fileName().c_str()); + CPPUNIT_ASSERT(file.tag() != nullptr); + file.tag()->setTitle(titleAfter); + file.tag()->setComment(newComment); + CPPUNIT_ASSERT(file.save()); + } + testRead(copy.fileName().c_str(), titleAfter, commentAfter); + CPPUNIT_ASSERT(fileEqual( + copy.fileName(), + TEST_FILE_PATH_C("changed.mod"))); + } + + void testPropertyInterface() { + Mod::Tag t; + PropertyMap properties; + properties["BLA"] = String("bla"); + properties["ARTIST"] = String("artist1"); + properties["ARTIST"].append("artist2"); + properties["TITLE"] = String("title"); + + PropertyMap unsupported = t.setProperties(properties); + CPPUNIT_ASSERT(unsupported.contains("BLA")); + CPPUNIT_ASSERT(unsupported.contains("ARTIST")); + CPPUNIT_ASSERT_EQUAL(properties["ARTIST"], unsupported["ARTIST"]); + CPPUNIT_ASSERT(!unsupported.contains("TITLE")); + } + + private: + void testRead(FileName fileName, const String &title, const String &comment) { + Mod::File file(fileName); + + CPPUNIT_ASSERT(file.isValid()); + + Mod::AudioProperties *p = file.audioProperties(); + Mod::Tag *t = file.tag(); + + CPPUNIT_ASSERT(nullptr != p); + CPPUNIT_ASSERT(nullptr != t); + + CPPUNIT_ASSERT_EQUAL(0, p->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); + CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); + CPPUNIT_ASSERT_EQUAL(8, p->channels()); + CPPUNIT_ASSERT_EQUAL(31U, p->instrumentCount()); + CPPUNIT_ASSERT_EQUAL((unsigned char)1, p->lengthInPatterns()); + CPPUNIT_ASSERT_EQUAL(title, t->title()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); + CPPUNIT_ASSERT_EQUAL(comment, t->comment()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); + CPPUNIT_ASSERT_EQUAL(0U, t->year()); + CPPUNIT_ASSERT_EQUAL(0U, t->track()); + CPPUNIT_ASSERT_EQUAL(String("StarTrekker"), t->trackerName()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMod); diff --git a/tests/taglib/test_mp4.cpp b/tests/taglib/test_mp4.cpp new file mode 100644 index 000000000..ac4bb1b3d --- /dev/null +++ b/tests/taglib/test_mp4.cpp @@ -0,0 +1,439 @@ +/*************************************************************************** + copyright : (C) 2008 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "mp4tag.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "mp4atom.h" +#include "mp4file.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestMP4 : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMP4); + CPPUNIT_TEST(testPropertiesAAC); + CPPUNIT_TEST(testPropertiesALAC); + CPPUNIT_TEST(testPropertiesM4V); + CPPUNIT_TEST(testFreeForm); + CPPUNIT_TEST(testCheckValid); + CPPUNIT_TEST(testHasTag); + CPPUNIT_TEST(testIsEmpty); + CPPUNIT_TEST(testUpdateStco); + CPPUNIT_TEST(testSaveExisingWhenIlstIsLast); + CPPUNIT_TEST(test64BitAtom); + CPPUNIT_TEST(testGnre); + CPPUNIT_TEST(testCovrRead); + CPPUNIT_TEST(testCovrWrite); + CPPUNIT_TEST(testCovrRead2); + CPPUNIT_TEST(testProperties); + CPPUNIT_TEST(testPropertiesMovement); + CPPUNIT_TEST(testFuzzedFile); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST(testWithZeroLengthAtom); + CPPUNIT_TEST_SUITE_END(); + + public: + void testPropertiesAAC() { + MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3708, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + CPPUNIT_ASSERT_EQUAL(MP4::AudioProperties::AAC, f.audioProperties()->codec()); + } + + void testPropertiesALAC() { + MP4::File f(TEST_FILE_PATH_C("empty_alac.m4a")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3705, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + CPPUNIT_ASSERT_EQUAL(MP4::AudioProperties::ALAC, f.audioProperties()->codec()); + } + + void testPropertiesM4V() { + MP4::File f(TEST_FILE_PATH_C("blank_video.m4v")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(975, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(96, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + CPPUNIT_ASSERT_EQUAL(MP4::AudioProperties::AAC, f.audioProperties()->codec()); + } + + void testCheckValid() { + MP4::File f(TEST_FILE_PATH_C("empty.aiff")); + CPPUNIT_ASSERT(!f.isValid()); + } + + void testHasTag() { + { + MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasMP4Tag()); + } + + ScopedFileCopy copy("no-tags", ".m4a"); + + { + MP4::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasMP4Tag()); + f.tag()->setTitle("TITLE"); + f.save(); + } + { + MP4::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasMP4Tag()); + } + } + + void testIsEmpty() { + MP4::Tag t1; + CPPUNIT_ASSERT(t1.isEmpty()); + t1.setArtist("Foo"); + CPPUNIT_ASSERT(!t1.isEmpty()); + + MP4::Tag t2; + t2.setItem("foo", "bar"); + CPPUNIT_ASSERT(!t2.isEmpty()); + } + + void testUpdateStco() { + ScopedFileCopy copy("no-tags", ".3g2"); + string filename = copy.fileName(); + + ByteVectorList data1; + + { + MP4::File f(filename.c_str()); + f.tag()->setArtist(ByteVector(3000, 'x')); + + MP4::Atoms a(&f); + MP4::Atom *stco = a.find("moov")->findall("stco", true)[0]; + f.seek(stco->offset + 12); + ByteVector data = f.readBlock(static_cast(stco->length - 12)); + unsigned int count = data.mid(0, 4).toUInt32BE(0); + int pos = 4; + while (count--) { + unsigned int offset = data.mid(pos, 4).toUInt32BE(0); + f.seek(offset); + data1.append(f.readBlock(20)); + pos += 4; + } + + f.save(); + } + + { + MP4::File f(filename.c_str()); + + MP4::Atoms a(&f); + MP4::Atom *stco = a.find("moov")->findall("stco", true)[0]; + f.seek(stco->offset + 12); + ByteVector data = f.readBlock(static_cast(stco->length - 12)); + unsigned int count = data.mid(0, 4).toUInt32BE(0); + int pos = 4, i = 0; + while (count--) { + unsigned int offset = data.mid(pos, 4).toUInt32BE(0); + f.seek(offset); + CPPUNIT_ASSERT_EQUAL(data1[i], f.readBlock(20)); + pos += 4; + i++; + } + } + } + + void testFreeForm() { + ScopedFileCopy copy("has-tags", ".m4a"); + string filename = copy.fileName(); + + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT(f.tag()->contains("----:com.apple.iTunes:iTunNORM")); + f.tag()->setItem("----:org.kde.TagLib:Foo", StringList("Bar")); + f.save(); + } + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT(f.tag()->contains("----:org.kde.TagLib:Foo")); + CPPUNIT_ASSERT_EQUAL(String("Bar"), + f.tag()->item("----:org.kde.TagLib:Foo").toStringList().front()); + f.save(); + } + } + + void testSaveExisingWhenIlstIsLast() { + ScopedFileCopy copy("ilst-is-last", ".m4a"); + string filename = copy.fileName(); + + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(String("82,164"), + f.tag()->item("----:com.apple.iTunes:replaygain_track_minmax").toStringList().front()); + CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f.tag()->artist()); + f.tag()->setComment("foo"); + f.save(); + } + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(String("82,164"), + f.tag()->item("----:com.apple.iTunes:replaygain_track_minmax").toStringList().front()); + CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f.tag()->artist()); + CPPUNIT_ASSERT_EQUAL(String("foo"), f.tag()->comment()); + } + } + + void test64BitAtom() { + ScopedFileCopy copy("64bit", ".mp4"); + string filename = copy.fileName(); + + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(true, f.tag()->itemMap()["cpil"].toBool()); + + MP4::Atoms atoms(&f); + MP4::Atom *moov = atoms.atoms[0]; + CPPUNIT_ASSERT_EQUAL(77LL, moov->length); + + f.tag()->setItem("pgap", true); + f.save(); + } + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(true, f.tag()->item("cpil").toBool()); + CPPUNIT_ASSERT_EQUAL(true, f.tag()->item("pgap").toBool()); + + MP4::Atoms atoms(&f); + MP4::Atom *moov = atoms.atoms[0]; + // original size + 'pgap' size + padding + CPPUNIT_ASSERT_EQUAL(77 + 25 + 974LL, moov->length); + } + } + + void testGnre() { + MP4::File f(TEST_FILE_PATH_C("gnre.m4a")); + CPPUNIT_ASSERT_EQUAL(Strawberry_TagLib::TagLib::String("Ska"), f.tag()->genre()); + } + + void testCovrRead() { + MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); + CPPUNIT_ASSERT(f.tag()->contains("covr")); + MP4::CoverArtList l = f.tag()->item("covr").toCoverArtList(); + CPPUNIT_ASSERT_EQUAL((size_t)2, l.size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); + CPPUNIT_ASSERT_EQUAL((size_t)79, l[0].data().size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); + CPPUNIT_ASSERT_EQUAL((size_t)287, l[1].data().size()); + } + + void testCovrWrite() { + ScopedFileCopy copy("has-tags", ".m4a"); + string filename = copy.fileName(); + + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT(f.tag()->contains("covr")); + MP4::CoverArtList l = f.tag()->item("covr").toCoverArtList(); + l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); + f.tag()->setItem("covr", l); + f.save(); + } + { + MP4::File f(filename.c_str()); + CPPUNIT_ASSERT(f.tag()->contains("covr")); + MP4::CoverArtList l = f.tag()->item("covr").toCoverArtList(); + CPPUNIT_ASSERT_EQUAL((size_t)3, l.size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); + CPPUNIT_ASSERT_EQUAL((size_t)79, l[0].data().size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); + CPPUNIT_ASSERT_EQUAL((size_t)287, l[1].data().size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[2].format()); + CPPUNIT_ASSERT_EQUAL((size_t)3, l[2].data().size()); + } + } + + void testCovrRead2() { + MP4::File f(TEST_FILE_PATH_C("covr-junk.m4a")); + CPPUNIT_ASSERT(f.tag()->contains("covr")); + MP4::CoverArtList l = f.tag()->item("covr").toCoverArtList(); + CPPUNIT_ASSERT_EQUAL((size_t)2, l.size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); + CPPUNIT_ASSERT_EQUAL((size_t)79, l[0].data().size()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); + CPPUNIT_ASSERT_EQUAL((size_t)287, l[1].data().size()); + } + + void testProperties() { + MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); + + PropertyMap tags = f.properties(); + + CPPUNIT_ASSERT_EQUAL(StringList("Test Artist"), tags["ARTIST"]); + + tags["TRACKNUMBER"] = StringList("2/4"); + tags["DISCNUMBER"] = StringList("3/5"); + tags["BPM"] = StringList("123"); + tags["ARTIST"] = StringList("Foo Bar"); + tags["COMPILATION"] = StringList("1"); + f.setProperties(tags); + + tags = f.properties(); + + CPPUNIT_ASSERT(f.tag()->contains("trkn")); + CPPUNIT_ASSERT_EQUAL(2, f.tag()->item("trkn").toIntPair().first); + CPPUNIT_ASSERT_EQUAL(4, f.tag()->item("trkn").toIntPair().second); + CPPUNIT_ASSERT_EQUAL(StringList("2/4"), tags["TRACKNUMBER"]); + + CPPUNIT_ASSERT(f.tag()->contains("disk")); + CPPUNIT_ASSERT_EQUAL(3, f.tag()->item("disk").toIntPair().first); + CPPUNIT_ASSERT_EQUAL(5, f.tag()->item("disk").toIntPair().second); + CPPUNIT_ASSERT_EQUAL(StringList("3/5"), tags["DISCNUMBER"]); + + CPPUNIT_ASSERT(f.tag()->contains("tmpo")); + CPPUNIT_ASSERT_EQUAL(123, f.tag()->item("tmpo").toInt()); + CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]); + + CPPUNIT_ASSERT(f.tag()->contains("\251ART")); + CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), f.tag()->item("\251ART").toStringList()); + CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]); + + CPPUNIT_ASSERT(f.tag()->contains("cpil")); + CPPUNIT_ASSERT_EQUAL(true, f.tag()->item("cpil").toBool()); + CPPUNIT_ASSERT_EQUAL(StringList("1"), tags["COMPILATION"]); + + tags["COMPILATION"] = StringList("0"); + f.setProperties(tags); + + tags = f.properties(); + + CPPUNIT_ASSERT(f.tag()->contains("cpil")); + CPPUNIT_ASSERT_EQUAL(false, f.tag()->item("cpil").toBool()); + CPPUNIT_ASSERT_EQUAL(StringList("0"), tags["COMPILATION"]); + + // Empty properties do not result in access violations + // when converting integers + tags["TRACKNUMBER"] = StringList(); + tags["DISCNUMBER"] = StringList(); + tags["BPM"] = StringList(); + tags["COMPILATION"] = StringList(); + f.setProperties(tags); + } + + void testPropertiesMovement() { + MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); + + PropertyMap tags = f.properties(); + + tags["WORK"] = StringList("Foo"); + tags["MOVEMENTNAME"] = StringList("Bar"); + tags["MOVEMENTNUMBER"] = StringList("2"); + tags["MOVEMENTCOUNT"] = StringList("3"); + tags["SHOWWORKMOVEMENT"] = StringList("1"); + f.setProperties(tags); + + tags = f.properties(); + + CPPUNIT_ASSERT(f.tag()->contains("\251wrk")); + CPPUNIT_ASSERT_EQUAL(StringList("Foo"), f.tag()->item("\251wrk").toStringList()); + CPPUNIT_ASSERT_EQUAL(StringList("Foo"), tags["WORK"]); + + CPPUNIT_ASSERT(f.tag()->contains("\251mvn")); + CPPUNIT_ASSERT_EQUAL(StringList("Bar"), f.tag()->item("\251mvn").toStringList()); + CPPUNIT_ASSERT_EQUAL(StringList("Bar"), tags["MOVEMENTNAME"]); + + CPPUNIT_ASSERT(f.tag()->contains("\251mvi")); + CPPUNIT_ASSERT_EQUAL(2, f.tag()->item("\251mvi").toInt()); + CPPUNIT_ASSERT_EQUAL(StringList("2"), tags["MOVEMENTNUMBER"]); + + CPPUNIT_ASSERT(f.tag()->contains("\251mvc")); + CPPUNIT_ASSERT_EQUAL(3, f.tag()->item("\251mvc").toInt()); + CPPUNIT_ASSERT_EQUAL(StringList("3"), tags["MOVEMENTCOUNT"]); + + CPPUNIT_ASSERT(f.tag()->contains("shwm")); + CPPUNIT_ASSERT_EQUAL(true, f.tag()->item("shwm").toBool()); + CPPUNIT_ASSERT_EQUAL(StringList("1"), tags["SHOWWORKMOVEMENT"]); + + tags["SHOWWORKMOVEMENT"] = StringList("0"); + f.setProperties(tags); + + tags = f.properties(); + + CPPUNIT_ASSERT(f.tag()->contains("shwm")); + CPPUNIT_ASSERT_EQUAL(false, f.tag()->item("shwm").toBool()); + CPPUNIT_ASSERT_EQUAL(StringList("0"), tags["SHOWWORKMOVEMENT"]); + + tags["WORK"] = StringList(); + tags["MOVEMENTNAME"] = StringList(); + tags["MOVEMENTNUMBER"] = StringList(); + tags["MOVEMENTCOUNT"] = StringList(); + tags["SHOWWORKMOVEMENT"] = StringList(); + f.setProperties(tags); + } + + void testFuzzedFile() { + MP4::File f(TEST_FILE_PATH_C("infloop.m4a")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testRepeatedSave() { + ScopedFileCopy copy("no-tags", ".m4a"); + + MP4::File f(copy.fileName().c_str()); + f.tag()->setTitle("0123456789"); + f.save(); + f.save(); + CPPUNIT_ASSERT_EQUAL(2862LL, f.find("0123456789")); + CPPUNIT_ASSERT_EQUAL(-1LL, f.find("0123456789", 2863)); + } + + void testWithZeroLengthAtom() { + MP4::File f(TEST_FILE_PATH_C("zero-length-mdat.m4a")); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(1115, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(22050, f.audioProperties()->sampleRate()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4); diff --git a/tests/taglib/test_mp4coverart.cpp b/tests/taglib/test_mp4coverart.cpp new file mode 100644 index 000000000..a9d2f3b00 --- /dev/null +++ b/tests/taglib/test_mp4coverart.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "mp4coverart.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestMP4CoverArt : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMP4CoverArt); + CPPUNIT_TEST(testSimple); + CPPUNIT_TEST(testList); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimple() { + MP4::CoverArt c(MP4::CoverArt::PNG, "foo"); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c.format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c.data()); + + MP4::CoverArt c2(c); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c2.format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c2.data()); + + MP4::CoverArt c3 = c; + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c3.format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c3.data()); + } + + void testList() { + MP4::CoverArtList l; + l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); + l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar")); + + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4CoverArt); diff --git a/tests/taglib/test_mp4item.cpp b/tests/taglib/test_mp4item.cpp new file mode 100644 index 000000000..5569ee212 --- /dev/null +++ b/tests/taglib/test_mp4item.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "mp4coverart.h" +#include "mp4item.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestMP4Item : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMP4Item); + CPPUNIT_TEST(testCoverArtList); + CPPUNIT_TEST_SUITE_END(); + + public: + void testCoverArtList() { + MP4::CoverArtList l; + l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); + l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar")); + + MP4::Item i(l); + MP4::CoverArtList l2 = i.toCoverArtList(); + + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data()); + CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); + CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4Item); diff --git a/tests/taglib/test_mpc.cpp b/tests/taglib/test_mpc.cpp new file mode 100644 index 000000000..9bcb7397b --- /dev/null +++ b/tests/taglib/test_mpc.cpp @@ -0,0 +1,173 @@ +/*************************************************************************** + copyright : (C) 2012 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "apetag.h" +#include "id3v1tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "mpcfile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestMPC : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMPC); + CPPUNIT_TEST(testPropertiesSV8); + CPPUNIT_TEST(testPropertiesSV7); + CPPUNIT_TEST(testPropertiesSV5); + CPPUNIT_TEST(testPropertiesSV4); + CPPUNIT_TEST(testFuzzedFile1); + CPPUNIT_TEST(testFuzzedFile2); + CPPUNIT_TEST(testFuzzedFile3); + CPPUNIT_TEST(testFuzzedFile4); + CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST_SUITE_END(); + + public: + void testPropertiesSV8() { + MPC::File f(TEST_FILE_PATH_C("sv8_header.mpc")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(8, f.audioProperties()->mpcVersion()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(1497, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(66014U, f.audioProperties()->sampleFrames()); + } + + void testPropertiesSV7() { + MPC::File f(TEST_FILE_PATH_C("click.mpc")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->mpcVersion()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(40, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(318, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1760U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(14221, f.audioProperties()->trackGain()); + CPPUNIT_ASSERT_EQUAL(19848, f.audioProperties()->trackPeak()); + CPPUNIT_ASSERT_EQUAL(14221, f.audioProperties()->albumGain()); + CPPUNIT_ASSERT_EQUAL(19848, f.audioProperties()->albumPeak()); + } + + void testPropertiesSV5() { + MPC::File f(TEST_FILE_PATH_C("sv5_header.mpc")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(5, f.audioProperties()->mpcVersion()); + CPPUNIT_ASSERT_EQUAL(26, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(26371, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1162944U, f.audioProperties()->sampleFrames()); + } + + void testPropertiesSV4() { + MPC::File f(TEST_FILE_PATH_C("sv4_header.mpc")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->mpcVersion()); + CPPUNIT_ASSERT_EQUAL(26, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(26371, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1162944U, f.audioProperties()->sampleFrames()); + } + + void testFuzzedFile1() { + MPC::File f(TEST_FILE_PATH_C("zerodiv.mpc")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testFuzzedFile2() { + MPC::File f(TEST_FILE_PATH_C("infloop.mpc")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testFuzzedFile3() { + MPC::File f(TEST_FILE_PATH_C("segfault.mpc")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testFuzzedFile4() { + MPC::File f(TEST_FILE_PATH_C("segfault2.mpc")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testStripAndProperties() { + ScopedFileCopy copy("click", ".mpc"); + + { + MPC::File f(copy.fileName().c_str()); + f.APETag(true)->setTitle("APE"); + f.ID3v1Tag(true)->setTitle("ID3v1"); + f.save(); + } + { + MPC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("APE"), f.properties()["TITLE"].front()); + f.strip(MPC::File::APE); + CPPUNIT_ASSERT_EQUAL(String("ID3v1"), f.properties()["TITLE"].front()); + f.strip(MPC::File::ID3v1); + CPPUNIT_ASSERT(f.properties().isEmpty()); + } + } + + void testRepeatedSave() { + ScopedFileCopy copy("click", ".mpc"); + + { + MPC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasAPETag()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + + f.APETag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.save(); + + f.APETag()->setTitle("0"); + f.save(); + + f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.APETag()->setTitle("01234 56789 ABCDE FGHIJ 01234 56789 ABCDE FGHIJ 01234 56789"); + f.save(); + } + { + MPC::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasAPETag()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMPC); diff --git a/tests/taglib/test_mpeg.cpp b/tests/taglib/test_mpeg.cpp new file mode 100644 index 000000000..86c8b1837 --- /dev/null +++ b/tests/taglib/test_mpeg.cpp @@ -0,0 +1,392 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tstring.h" +#include "tpropertymap.h" +#include "tfile.h" +#include "mpegfile.h" +#include "id3v2tag.h" +#include "id3v1tag.h" +#include "apetag.h" +#include "mpegproperties.h" +#include "xingheader.h" +#include "mpegheader.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestMPEG : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestMPEG); + CPPUNIT_TEST(testAudioPropertiesXingHeaderCBR); + CPPUNIT_TEST(testAudioPropertiesXingHeaderVBR); + CPPUNIT_TEST(testAudioPropertiesVBRIHeader); + CPPUNIT_TEST(testAudioPropertiesNoVBRHeaders); + CPPUNIT_TEST(testSkipInvalidFrames1); + CPPUNIT_TEST(testSkipInvalidFrames2); + CPPUNIT_TEST(testSkipInvalidFrames3); + CPPUNIT_TEST(testVersion2DurationWithXingHeader); + CPPUNIT_TEST(testSaveID3v24); + CPPUNIT_TEST(testSaveID3v23); + CPPUNIT_TEST(testDuplicateID3v2); + CPPUNIT_TEST(testFuzzedFile); + CPPUNIT_TEST(testFrameOffset); + CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testRepeatedSave1); + CPPUNIT_TEST(testRepeatedSave2); + CPPUNIT_TEST(testRepeatedSave3); + CPPUNIT_TEST(testEmptyID3v2); + CPPUNIT_TEST(testEmptyID3v1); + CPPUNIT_TEST(testEmptyAPE); + CPPUNIT_TEST(testIgnoreGarbage); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAudioPropertiesXingHeaderCBR() { + MPEG::File f(TEST_FILE_PATH_C("lame_cbr.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(1887, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(1887164, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(MPEG::XingHeader::Xing, f.audioProperties()->xingHeader()->type()); + } + + void testAudioPropertiesXingHeaderVBR() { + MPEG::File f(TEST_FILE_PATH_C("lame_vbr.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(1887, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(1887164, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(70, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(MPEG::XingHeader::Xing, f.audioProperties()->xingHeader()->type()); + } + + void testAudioPropertiesVBRIHeader() { + MPEG::File f(TEST_FILE_PATH_C("rare_frames.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(222, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(222198, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(233, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(MPEG::XingHeader::VBRI, f.audioProperties()->xingHeader()->type()); + } + + void testAudioPropertiesNoVBRHeaders() { + MPEG::File f(TEST_FILE_PATH_C("bladeenc.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3553, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT(!f.audioProperties()->xingHeader()); + + const long long last = f.lastFrameOffset(); + const MPEG::Header lastHeader(&f, last, false); + + CPPUNIT_ASSERT_EQUAL(28213LL, last); + CPPUNIT_ASSERT_EQUAL(209, lastHeader.frameLength()); + } + + void testSkipInvalidFrames1() { + MPEG::File f(TEST_FILE_PATH_C("invalid-frames1.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(392, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(160, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT(!f.audioProperties()->xingHeader()); + } + + void testSkipInvalidFrames2() { + MPEG::File f(TEST_FILE_PATH_C("invalid-frames2.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(314, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(192, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT(!f.audioProperties()->xingHeader()); + } + + void testSkipInvalidFrames3() { + MPEG::File f(TEST_FILE_PATH_C("invalid-frames3.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(183, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(320, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT(!f.audioProperties()->xingHeader()); + } + + void testVersion2DurationWithXingHeader() { + MPEG::File f(TEST_FILE_PATH_C("mpeg2.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(5387, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(5387285, f.audioProperties()->lengthInMilliseconds()); + } + + void testSaveID3v24() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + String xxx = ByteVector(254, 'X'); + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); + + f.tag()->setTitle(xxx); + f.tag()->setArtist("Artist A"); + f.save(MPEG::File::AllTags, File::StripOthers, ID3v2::v4); + CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); + } + { + MPEG::File f2(newname.c_str()); + CPPUNIT_ASSERT_EQUAL((unsigned int)4, f2.ID3v2Tag()->header()->majorVersion()); + CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); + CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); + } + } + + void testSaveID3v23() { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + String xxx = ByteVector(254, 'X'); + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); + + f.tag()->setTitle(xxx); + f.tag()->setArtist("Artist A"); + f.save(MPEG::File::AllTags, File::StripOthers, ID3v2::v3); + CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); + } + { + MPEG::File f2(newname.c_str()); + CPPUNIT_ASSERT_EQUAL((unsigned int)3, f2.ID3v2Tag()->header()->majorVersion()); + CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); + CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); + } + } + + void testDuplicateID3v2() { + MPEG::File f(TEST_FILE_PATH_C("duplicate_id3v2.mp3")); + + // duplicate_id3v2.mp3 has duplicate ID3v2 tags. + // Sample rate will be 32000 if can't skip the second tag. + + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + } + + void testFuzzedFile() { + MPEG::File f(TEST_FILE_PATH_C("excessive_alloc.mp3")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testFrameOffset() { + { + MPEG::File f(TEST_FILE_PATH_C("ape.mp3")); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(0x0000LL, f.firstFrameOffset()); + CPPUNIT_ASSERT_EQUAL(0x1FD6LL, f.lastFrameOffset()); + } + { + MPEG::File f(TEST_FILE_PATH_C("ape-id3v1.mp3")); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(0x0000LL, f.firstFrameOffset()); + CPPUNIT_ASSERT_EQUAL(0x1FD6LL, f.lastFrameOffset()); + } + { + MPEG::File f(TEST_FILE_PATH_C("ape-id3v2.mp3")); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(0x041ALL, f.firstFrameOffset()); + CPPUNIT_ASSERT_EQUAL(0x23F0LL, f.lastFrameOffset()); + } + } + + void testStripAndProperties() { + ScopedFileCopy copy("xing", ".mp3"); + + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle("ID3v2"); + f.APETag(true)->setTitle("APE"); + f.ID3v1Tag(true)->setTitle("ID3v1"); + f.save(); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("ID3v2"), f.properties()["TITLE"].front()); + f.strip(MPEG::File::ID3v2); + CPPUNIT_ASSERT_EQUAL(String("APE"), f.properties()["TITLE"].front()); + f.strip(MPEG::File::APE); + CPPUNIT_ASSERT_EQUAL(String("ID3v1"), f.properties()["TITLE"].front()); + f.strip(MPEG::File::ID3v1); + CPPUNIT_ASSERT(f.properties().isEmpty()); + } + } + + void testRepeatedSave1() { + ScopedFileCopy copy("xing", ".mp3"); + + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle(std::string(4096, 'X').c_str()); + f.save(); + } + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle(""); + f.save(); + f.ID3v2Tag(true)->setTitle(std::string(4096, 'X').c_str()); + f.save(); + CPPUNIT_ASSERT_EQUAL(5141LL, f.firstFrameOffset()); + } + } + + void testRepeatedSave2() { + ScopedFileCopy copy("xing", ".mp3"); + + MPEG::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle("0123456789"); + f.save(); + f.save(); + CPPUNIT_ASSERT_EQUAL(-1LL, f.find("ID3", 3)); + } + + void testRepeatedSave3() { + ScopedFileCopy copy("xing", ".mp3"); + + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasAPETag()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + + f.APETag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.save(); + f.APETag()->setTitle("0"); + f.save(); + f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.APETag()->setTitle("01234 56789 ABCDE FGHIJ 01234 56789 ABCDE FGHIJ 01234 56789"); + f.save(); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasAPETag()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + } + } + + void testEmptyID3v2() { + ScopedFileCopy copy("xing", ".mp3"); + + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle("0123456789"); + f.save(MPEG::File::ID3v2); + } + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle(""); + f.save(MPEG::File::ID3v2, File::StripNone); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + } + + void testEmptyID3v1() { + ScopedFileCopy copy("xing", ".mp3"); + + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v1Tag(true)->setTitle("0123456789"); + f.save(MPEG::File::ID3v1); + } + { + MPEG::File f(copy.fileName().c_str()); + f.ID3v1Tag(true)->setTitle(""); + f.save(MPEG::File::ID3v1, File::StripNone); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + } + } + + void testEmptyAPE() { + ScopedFileCopy copy("xing", ".mp3"); + + { + MPEG::File f(copy.fileName().c_str()); + f.APETag(true)->setTitle("0123456789"); + f.save(MPEG::File::APE); + } + { + MPEG::File f(copy.fileName().c_str()); + f.APETag(true)->setTitle(""); + f.save(MPEG::File::APE, File::StripNone); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasAPETag()); + } + } + + void testIgnoreGarbage() { + const ScopedFileCopy copy("garbage", ".mp3"); + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(2255LL, f.firstFrameOffset()); + CPPUNIT_ASSERT_EQUAL(6015LL, f.lastFrameOffset()); + CPPUNIT_ASSERT_EQUAL(String("Title A"), f.ID3v2Tag()->title()); + f.ID3v2Tag()->setTitle("Title B"); + f.save(); + } + { + MPEG::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String("Title B"), f.ID3v2Tag()->title()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG); diff --git a/tests/taglib/test_ogg.cpp b/tests/taglib/test_ogg.cpp new file mode 100644 index 000000000..c827f7194 --- /dev/null +++ b/tests/taglib/test_ogg.cpp @@ -0,0 +1,218 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "oggfile.h" +#include "vorbisfile.h" +#include "oggpageheader.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestOGG : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestOGG); + CPPUNIT_TEST(testSimple); + CPPUNIT_TEST(testSplitPackets1); + CPPUNIT_TEST(testSplitPackets2); + CPPUNIT_TEST(testDictInterface1); + CPPUNIT_TEST(testDictInterface2); + CPPUNIT_TEST(testAudioProperties); + CPPUNIT_TEST(testPageChecksum); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimple() { + ScopedFileCopy copy("empty", ".ogg"); + string newname = copy.fileName(); + + { + Ogg::Vorbis::File f(newname.c_str()); + f.tag()->setArtist("The Artist"); + f.save(); + } + { + Ogg::Vorbis::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("The Artist"), f.tag()->artist()); + } + } + + void testSplitPackets1() { + ScopedFileCopy copy("empty", ".ogg"); + string newname = copy.fileName(); + + const String text = longText(128 * 1024, true); + + { + Ogg::Vorbis::File f(newname.c_str()); + f.tag()->setTitle(text); + f.save(); + } + { + Ogg::Vorbis::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(136383LL, f.length()); + CPPUNIT_ASSERT_EQUAL(19, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)30, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)131127, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)3832, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL(text, f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + + f.tag()->setTitle("ABCDE"); + f.save(); + } + { + Ogg::Vorbis::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(4370LL, f.length()); + CPPUNIT_ASSERT_EQUAL(3, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)30, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)60, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)3832, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL(String("ABCDE"), f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + } + } + + void testSplitPackets2() { + ScopedFileCopy copy("empty", ".ogg"); + string newname = copy.fileName(); + + const String text = longText(60890, true); + + { + Ogg::Vorbis::File f(newname.c_str()); + f.tag()->setTitle(text); + f.save(); + } + { + Ogg::Vorbis::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(text, f.tag()->title()); + + f.tag()->setTitle("ABCDE"); + f.save(); + } + { + Ogg::Vorbis::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(String("ABCDE"), f.tag()->title()); + } + } + + void testDictInterface1() { + ScopedFileCopy copy("empty", ".ogg"); + string newname = copy.fileName(); + + Ogg::Vorbis::File f(newname.c_str()); + + CPPUNIT_ASSERT_EQUAL((size_t)0, f.tag()->properties().size()); + + PropertyMap newTags; + StringList values("value 1"); + values.append("value 2"); + newTags["ARTIST"] = values; + f.tag()->setProperties(newTags); + + PropertyMap map = f.tag()->properties(); + CPPUNIT_ASSERT_EQUAL((size_t)1, map.size()); + CPPUNIT_ASSERT_EQUAL((size_t)2, map["ARTIST"].size()); + CPPUNIT_ASSERT_EQUAL(String("value 1"), map["ARTIST"][0]); + } + + void testDictInterface2() { + ScopedFileCopy copy("test", ".ogg"); + string newname = copy.fileName(); + + Ogg::Vorbis::File f(newname.c_str()); + PropertyMap tags = f.tag()->properties(); + + CPPUNIT_ASSERT_EQUAL((size_t)2, tags["UNUSUALTAG"].size()); + CPPUNIT_ASSERT_EQUAL(String("usual value"), tags["UNUSUALTAG"][0]); + CPPUNIT_ASSERT_EQUAL(String("another value"), tags["UNUSUALTAG"][1]); + CPPUNIT_ASSERT_EQUAL( + String("\xC3\xB6\xC3\xA4\xC3\xBC\x6F\xCE\xA3\xC3\xB8", String::UTF8), + tags["UNICODETAG"][0]); + + tags["UNICODETAG"][0] = String( + "\xCE\xBD\xCE\xB5\xCF\x89\x20\xCE\xBD\xCE\xB1\xCE\xBB\xCF\x85\xCE\xB5", + String::UTF8); + tags.erase("UNUSUALTAG"); + f.tag()->setProperties(tags); + CPPUNIT_ASSERT_EQUAL( + String("\xCE\xBD\xCE\xB5\xCF\x89\x20\xCE\xBD\xCE\xB1\xCE\xBB\xCF\x85\xCE\xB5", String::UTF8), + f.tag()->properties()["UNICODETAG"][0]); + CPPUNIT_ASSERT_EQUAL(false, f.tag()->properties().contains("UNUSUALTAG")); + } + + void testAudioProperties() { + Ogg::Vorbis::File f(TEST_FILE_PATH_C("empty.ogg")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(9, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->vorbisVersion()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrateMaximum()); + CPPUNIT_ASSERT_EQUAL(112000, f.audioProperties()->bitrateNominal()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrateMinimum()); + } + + void testPageChecksum() { + ScopedFileCopy copy("empty", ".ogg"); + + { + Ogg::Vorbis::File f(copy.fileName().c_str()); + f.tag()->setArtist("The Artist"); + f.save(); + + f.seek(0x50); + CPPUNIT_ASSERT_EQUAL((unsigned int)0x3d3bd92d, f.readBlock(4).toUInt32BE(0)); + } + { + Ogg::Vorbis::File f(copy.fileName().c_str()); + f.tag()->setArtist("The Artist 2"); + f.save(); + + f.seek(0x50); + CPPUNIT_ASSERT_EQUAL((unsigned int)0xd985291c, f.readBlock(4).toUInt32BE(0)); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestOGG); diff --git a/tests/taglib/test_oggflac.cpp b/tests/taglib/test_oggflac.cpp new file mode 100644 index 000000000..4c2e8855f --- /dev/null +++ b/tests/taglib/test_oggflac.cpp @@ -0,0 +1,117 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tstringlist.h" +#include "tbytevectorlist.h" +#include "oggfile.h" +#include "oggflacfile.h" +#include "oggpageheader.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestOggFLAC : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestOggFLAC); + CPPUNIT_TEST(testFramingBit); + CPPUNIT_TEST(testFuzzedFile); + CPPUNIT_TEST(testSplitPackets); + CPPUNIT_TEST_SUITE_END(); + + public: + void testFramingBit() { + ScopedFileCopy copy("empty_flac", ".oga"); + string newname = copy.fileName(); + + { + Ogg::FLAC::File f(newname.c_str()); + f.tag()->setArtist("The Artist"); + f.save(); + } + { + Ogg::FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(String("The Artist"), f.tag()->artist()); + + f.seek(0, File::End); + CPPUNIT_ASSERT_EQUAL(9134LL, f.tell()); + } + } + + void testFuzzedFile() { + Ogg::FLAC::File f(TEST_FILE_PATH_C("segfault.oga")); + CPPUNIT_ASSERT(!f.isValid()); + } + + void testSplitPackets() { + ScopedFileCopy copy("empty_flac", ".oga"); + string newname = copy.fileName(); + + const String text = longText(128 * 1024, true); + + { + Ogg::FLAC::File f(newname.c_str()); + f.tag()->setTitle(text); + f.save(); + } + { + Ogg::FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(141141LL, f.length()); + CPPUNIT_ASSERT_EQUAL(21, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)51, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)131126, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)22, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL((size_t)8196, f.packet(3).size()); + CPPUNIT_ASSERT_EQUAL(text, f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3705, f.audioProperties()->lengthInMilliseconds()); + + f.tag()->setTitle("ABCDE"); + f.save(); + } + { + Ogg::FLAC::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(9128LL, f.length()); + CPPUNIT_ASSERT_EQUAL(5, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)51, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)59, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)22, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL((size_t)8196, f.packet(3).size()); + CPPUNIT_ASSERT_EQUAL(String("ABCDE"), f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3705, f.audioProperties()->lengthInMilliseconds()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestOggFLAC); diff --git a/tests/taglib/test_opus.cpp b/tests/taglib/test_opus.cpp new file mode 100644 index 000000000..7b4350a3c --- /dev/null +++ b/tests/taglib/test_opus.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** + copyright : (C) 2012 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tbytevectorlist.h" +#include "opusfile.h" +#include "oggpageheader.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestOpus : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestOpus); + CPPUNIT_TEST(testAudioProperties); + CPPUNIT_TEST(testReadComments); + CPPUNIT_TEST(testWriteComments); + CPPUNIT_TEST(testSplitPackets); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAudioProperties() { + Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(7737, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(37, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->inputSampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->opusVersion()); + } + + void testReadComments() { + Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus")); + CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f.tag()->fieldListMap()["ENCODER"]); + CPPUNIT_ASSERT(f.tag()->fieldListMap().contains("TESTDESCRIPTION")); + CPPUNIT_ASSERT(!f.tag()->fieldListMap().contains("ARTIST")); + CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f.tag()->vendorID()); + } + + void testWriteComments() { + ScopedFileCopy copy("correctness_gain_silent_output", ".opus"); + string filename = copy.fileName(); + + { + Ogg::Opus::File f(filename.c_str()); + f.tag()->setArtist("Your Tester"); + f.save(); + } + { + Ogg::Opus::File f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f.tag()->fieldListMap()["ENCODER"]); + CPPUNIT_ASSERT(f.tag()->fieldListMap().contains("TESTDESCRIPTION")); + CPPUNIT_ASSERT_EQUAL(StringList("Your Tester"), f.tag()->fieldListMap()["ARTIST"]); + CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f.tag()->vendorID()); + } + } + + void testSplitPackets() { + ScopedFileCopy copy("correctness_gain_silent_output", ".opus"); + string newname = copy.fileName(); + + const String text = longText(128 * 1024, true); + + { + Ogg::Opus::File f(newname.c_str()); + f.tag()->setTitle(text); + f.save(); + } + { + Ogg::Opus::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(167534LL, f.length()); + CPPUNIT_ASSERT_EQUAL(27, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)19, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)131380, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)5, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL((size_t)5, f.packet(3).size()); + CPPUNIT_ASSERT_EQUAL(text, f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(7737, f.audioProperties()->lengthInMilliseconds()); + + f.tag()->setTitle("ABCDE"); + f.save(); + } + { + Ogg::Opus::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(35521LL, f.length()); + CPPUNIT_ASSERT_EQUAL(11, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)19, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)313, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)5, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL((size_t)5, f.packet(3).size()); + CPPUNIT_ASSERT_EQUAL(String("ABCDE"), f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(7737, f.audioProperties()->lengthInMilliseconds()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestOpus); diff --git a/tests/taglib/test_propertymap.cpp b/tests/taglib/test_propertymap.cpp new file mode 100644 index 000000000..e48c4abf6 --- /dev/null +++ b/tests/taglib/test_propertymap.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + copyright : (C) 2012 by Michael Helmling + email : helmling@mathematik.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * 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 "tpropertymap.h" +#include "tag.h" +#include "id3v1tag.h" +#include "utils.h" + +using namespace Strawberry_TagLib::TagLib; + +class TestPropertyMap : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestPropertyMap); + CPPUNIT_TEST(testInvalidKeys); + CPPUNIT_TEST(testGetSet); + CPPUNIT_TEST_SUITE_END(); + + public: + void testInvalidKeys() { + PropertyMap map1; + CPPUNIT_ASSERT(map1.isEmpty()); + map1[L"\x00c4\x00d6\x00dc"].append("test"); + CPPUNIT_ASSERT_EQUAL(map1.size(), (size_t)1); + + PropertyMap map2; + map2[L"\x00c4\x00d6\x00dc"].append("test"); + CPPUNIT_ASSERT(map1 == map2); + CPPUNIT_ASSERT(map1.contains(map2)); + + map2["ARTIST"] = String("Test Artist"); + CPPUNIT_ASSERT(map1 != map2); + CPPUNIT_ASSERT(map2.contains(map1)); + + map2["\xc4\xd6\xdc"].append("test 2"); + map2[L"\x00c4\x00d6\x00dc"].append("test 2"); + CPPUNIT_ASSERT(!map2.contains(map1)); + } + + void testGetSet() { + ID3v1::Tag tag; + + tag.setTitle("Test Title"); + tag.setArtist("Test Artist"); + tag.setAlbum("Test Album"); + tag.setYear(2015); + tag.setTrack(10); + + { + PropertyMap prop = tag.properties(); + CPPUNIT_ASSERT_EQUAL(String("Test Title"), prop["TITLE"].front()); + CPPUNIT_ASSERT_EQUAL(String("Test Artist"), prop["ARTIST"].front()); + CPPUNIT_ASSERT_EQUAL(String("Test Album"), prop["ALBUM"].front()); + CPPUNIT_ASSERT_EQUAL(String("2015"), prop["DATE"].front()); + CPPUNIT_ASSERT_EQUAL(String("10"), prop["TRACKNUMBER"].front()); + + prop["TITLE"].front() = "Test Title 2"; + prop["ARTIST"].front() = "Test Artist 2"; + prop["TRACKNUMBER"].front() = "5"; + + tag.setProperties(prop); + } + + CPPUNIT_ASSERT_EQUAL(String("Test Title 2"), tag.title()); + CPPUNIT_ASSERT_EQUAL(String("Test Artist 2"), tag.artist()); + CPPUNIT_ASSERT_EQUAL(5U, tag.track()); + + tag.setProperties(PropertyMap()); + + CPPUNIT_ASSERT_EQUAL(String(""), tag.title()); + CPPUNIT_ASSERT_EQUAL(String(""), tag.artist()); + CPPUNIT_ASSERT_EQUAL(0U, tag.track()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestPropertyMap); diff --git a/tests/taglib/test_riff.cpp b/tests/taglib/test_riff.cpp new file mode 100644 index 000000000..e4fdf1f0b --- /dev/null +++ b/tests/taglib/test_riff.cpp @@ -0,0 +1,288 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "tag.h" +#include "tbytevectorlist.h" +#include "rifffile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class PublicRIFF : public RIFF::File { + public: + explicit PublicRIFF(FileName file) : RIFF::File(file, BigEndian) {}; + unsigned int riffSize() { return RIFF::File::riffSize(); }; + size_t chunkCount() { return RIFF::File::chunkCount(); }; + long long chunkOffset(unsigned int i) { return RIFF::File::chunkOffset(i); }; + unsigned int chunkPadding(unsigned int i) { return RIFF::File::chunkPadding(i); }; + unsigned int chunkDataSize(unsigned int i) { return RIFF::File::chunkDataSize(i); }; + ByteVector chunkName(unsigned int i) { return RIFF::File::chunkName(i); }; + ByteVector chunkData(unsigned int i) { return RIFF::File::chunkData(i); }; + void setChunkData(unsigned int i, const ByteVector &data) { + RIFF::File::setChunkData(i, data); + } + void setChunkData(const ByteVector &name, const ByteVector &data) { + RIFF::File::setChunkData(name, data); + }; + Strawberry_TagLib::TagLib::Tag *tag() const override { return nullptr; } + Strawberry_TagLib::TagLib::AudioProperties *audioProperties() const override { return nullptr; } + bool save() override { return false; } + void removeChunk(unsigned int i) { RIFF::File::removeChunk(i); } + void removeChunk(const ByteVector &name) { RIFF::File::removeChunk(name); } +}; + +class TestRIFF : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestRIFF); + CPPUNIT_TEST(testPadding); + CPPUNIT_TEST(testLastChunkAtEvenPosition); + CPPUNIT_TEST(testLastChunkAtEvenPosition2); + CPPUNIT_TEST(testLastChunkAtEvenPosition3); + CPPUNIT_TEST(testChunkOffset); + CPPUNIT_TEST_SUITE_END(); + + public: + void testPadding() { + ScopedFileCopy copy("empty", ".aiff"); + string filename = copy.fileName(); + + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((long long)(0x1728 + 8), f.chunkOffset(2)); + + f.setChunkData("TEST", "foo"); + } + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f.chunkData(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(3), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL((long long)(0x1728 + 8), f.chunkOffset(2)); + + f.setChunkData("SSND", "abcd"); + + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(1)); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f.chunkData(1)); + + f.seek(f.chunkOffset(1)); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f.readBlock(4)); + + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f.chunkData(2)); + + f.seek(f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f.readBlock(3)); + } + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(1)); + CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f.chunkData(1)); + + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f.chunkData(2)); + } + } + + void testLastChunkAtEvenPosition() { + ScopedFileCopy copy("noise", ".aif"); + string filename = copy.fileName(); + + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL((long long)(0xff0 + 8), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4400), f.length()); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4399 - 8), f.riffSize()); + f.setChunkData("TEST", "abcd"); + CPPUNIT_ASSERT_EQUAL((long long)(4088), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4408), f.chunkOffset(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4), f.chunkDataSize(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(0), f.chunkPadding(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4412 - 8), f.riffSize()); + } + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL((long long)(4088), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4408), f.chunkOffset(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4), f.chunkDataSize(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(0), f.chunkPadding(3)); + CPPUNIT_ASSERT_EQUAL((long long)(4412), f.length()); + } + } + + void testLastChunkAtEvenPosition2() { + ScopedFileCopy copy("noise_odd", ".aif"); + string filename = copy.fileName(); + + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL((long long)(0xff0 + 8), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(0), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4399), f.length()); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4399 - 8), f.riffSize()); + f.setChunkData("TEST", "abcd"); + CPPUNIT_ASSERT_EQUAL((long long)(4088), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4408), f.chunkOffset(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4), f.chunkDataSize(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(0), f.chunkPadding(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4412 - 8), f.riffSize()); + } + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL((long long)(4088), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4408), f.chunkOffset(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4), f.chunkDataSize(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(0), f.chunkPadding(3)); + CPPUNIT_ASSERT_EQUAL((long long)(4412), f.length()); + } + } + + void testLastChunkAtEvenPosition3() { + ScopedFileCopy copy("noise_odd", ".aif"); + string filename = copy.fileName(); + + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL((long long)(0xff0 + 8), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(0), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4399), f.length()); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4399 - 8), f.riffSize()); + f.setChunkData("TEST", "abc"); + CPPUNIT_ASSERT_EQUAL((long long)(4088), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4408), f.chunkOffset(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(3), f.chunkDataSize(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(4412 - 8), f.riffSize()); + } + { + PublicRIFF f(filename.c_str()); + CPPUNIT_ASSERT_EQUAL((long long)(4088), f.chunkOffset(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(311), f.chunkDataSize(2)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(2)); + CPPUNIT_ASSERT_EQUAL((long long)(4408), f.chunkOffset(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(3), f.chunkDataSize(3)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(3)); + CPPUNIT_ASSERT_EQUAL((unsigned int)(1), f.chunkPadding(3)); + CPPUNIT_ASSERT_EQUAL((long long)(4412), f.length()); + } + } + + void testChunkOffset() { + ScopedFileCopy copy("empty", ".aiff"); + string filename = copy.fileName(); + + PublicRIFF f(filename.c_str()); + + CPPUNIT_ASSERT_EQUAL(5928U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(5936LL, f.length()); + CPPUNIT_ASSERT_EQUAL(ByteVector("COMM"), f.chunkName(0)); + CPPUNIT_ASSERT_EQUAL((long long)(0x000C + 8), f.chunkOffset(0)); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.chunkName(1)); + CPPUNIT_ASSERT_EQUAL((long long)(0x0026 + 8), f.chunkOffset(1)); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.chunkName(2)); + CPPUNIT_ASSERT_EQUAL((long long)(0x1728 + 8), f.chunkOffset(2)); + + const ByteVector data(0x400, ' '); + f.setChunkData("SSND", data); + CPPUNIT_ASSERT_EQUAL(1070U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(1078LL, f.length()); + CPPUNIT_ASSERT_EQUAL((long long)(0x000C + 8), f.chunkOffset(0)); + CPPUNIT_ASSERT_EQUAL((long long)(0x0026 + 8), f.chunkOffset(1)); + CPPUNIT_ASSERT_EQUAL((long long)(0x042E + 8), f.chunkOffset(2)); + + f.seek(f.chunkOffset(0) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("COMM"), f.readBlock(4)); + f.seek(f.chunkOffset(1) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.readBlock(4)); + f.seek(f.chunkOffset(2) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); + + f.setChunkData(0, data); + CPPUNIT_ASSERT_EQUAL(2076U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(2084LL, f.length()); + CPPUNIT_ASSERT_EQUAL((long long)(0x000C + 8), f.chunkOffset(0)); + CPPUNIT_ASSERT_EQUAL((long long)(0x0414 + 8), f.chunkOffset(1)); + CPPUNIT_ASSERT_EQUAL((long long)(0x081C + 8), f.chunkOffset(2)); + + f.seek(f.chunkOffset(0) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("COMM"), f.readBlock(4)); + f.seek(f.chunkOffset(1) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f.readBlock(4)); + f.seek(f.chunkOffset(2) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); + + f.removeChunk("SSND"); + CPPUNIT_ASSERT_EQUAL(1044U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL(1052LL, f.length()); + CPPUNIT_ASSERT_EQUAL((long long)(0x000C + 8), f.chunkOffset(0)); + CPPUNIT_ASSERT_EQUAL((long long)(0x0414 + 8), f.chunkOffset(1)); + + f.seek(f.chunkOffset(0) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("COMM"), f.readBlock(4)); + f.seek(f.chunkOffset(1) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); + + f.removeChunk(0); + CPPUNIT_ASSERT_EQUAL(12U, f.riffSize()); + CPPUNIT_ASSERT_EQUAL((long long)(0x000C + 8), f.chunkOffset(0)); + + f.seek(f.chunkOffset(0) - 8); + CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f.readBlock(4)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestRIFF); diff --git a/tests/taglib/test_s3m.cpp b/tests/taglib/test_s3m.cpp new file mode 100644 index 000000000..8fa5ba2f4 --- /dev/null +++ b/tests/taglib/test_s3m.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + 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 * + * 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 "s3mfile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +static const String titleBefore("test song name"); +static const String titleAfter("changed title"); + +static const String commentBefore( + "This is an instrument name.\n" + "Module file formats\n" + "abuse instrument names\n" + "as multiline comments.\n" + " "); + +static const String newComment( + "This is an instrument name!\n" + "Module file formats\n" + "abuse instrument names\n" + "as multiline comments.\n" + "-----------------------------------\n" + "This line will be dropped and the previous is truncated."); + +static const String commentAfter( + "This is an instrument name!\n" + "Module file formats\n" + "abuse instrument names\n" + "as multiline comments.\n" + "---------------------------"); + +class TestS3M : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestS3M); + CPPUNIT_TEST(testReadTags); + CPPUNIT_TEST(testWriteTags); + CPPUNIT_TEST_SUITE_END(); + + public: + void testReadTags() { + testRead(TEST_FILE_PATH_C("test.s3m"), titleBefore, commentBefore); + } + + void testWriteTags() { + ScopedFileCopy copy("test", ".s3m"); + { + S3M::File file(copy.fileName().c_str()); + CPPUNIT_ASSERT(file.tag() != nullptr); + file.tag()->setTitle(titleAfter); + file.tag()->setComment(newComment); + file.tag()->setTrackerName("won't be saved"); + CPPUNIT_ASSERT(file.save()); + } + testRead(copy.fileName().c_str(), titleAfter, commentAfter); + CPPUNIT_ASSERT(fileEqual( + copy.fileName(), + TEST_FILE_PATH_C("changed.s3m"))); + } + + private: + void testRead(FileName fileName, const String &title, const String &comment) { + S3M::File file(fileName); + + CPPUNIT_ASSERT(file.isValid()); + + S3M::AudioProperties *p = file.audioProperties(); + Mod::Tag *t = file.tag(); + + CPPUNIT_ASSERT(nullptr != p); + CPPUNIT_ASSERT(nullptr != t); + + CPPUNIT_ASSERT_EQUAL(0, p->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); + CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, p->channels()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->lengthInPatterns()); + CPPUNIT_ASSERT_EQUAL(false, p->stereo()); + CPPUNIT_ASSERT_EQUAL((unsigned short)5, p->sampleCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->patternCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->flags()); + CPPUNIT_ASSERT_EQUAL((unsigned short)4896, p->trackerVersion()); + CPPUNIT_ASSERT_EQUAL((unsigned short)2, p->fileFormatVersion()); + CPPUNIT_ASSERT_EQUAL((unsigned char)64, p->globalVolume()); + CPPUNIT_ASSERT_EQUAL((unsigned char)48, p->masterVolume()); + CPPUNIT_ASSERT_EQUAL((unsigned char)125, p->tempo()); + CPPUNIT_ASSERT_EQUAL((unsigned char)6, p->bpmSpeed()); + CPPUNIT_ASSERT_EQUAL(title, t->title()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); + CPPUNIT_ASSERT_EQUAL(comment, t->comment()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); + CPPUNIT_ASSERT_EQUAL(0U, t->year()); + CPPUNIT_ASSERT_EQUAL(0U, t->track()); + CPPUNIT_ASSERT_EQUAL(String("ScreamTracker III"), t->trackerName()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestS3M); diff --git a/tests/taglib/test_speex.cpp b/tests/taglib/test_speex.cpp new file mode 100644 index 000000000..8b1fc1cbc --- /dev/null +++ b/tests/taglib/test_speex.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + 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 "speexfile.h" +#include "oggpageheader.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestSpeex : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestSpeex); + CPPUNIT_TEST(testAudioProperties); + CPPUNIT_TEST(testSplitPackets); + CPPUNIT_TEST_SUITE_END(); + + public: + void testAudioProperties() { + Ogg::Speex::File f(TEST_FILE_PATH_C("empty.spx")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(53, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(-1, f.audioProperties()->bitrateNominal()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + } + + void testSplitPackets() { + ScopedFileCopy copy("empty", ".spx"); + string newname = copy.fileName(); + + const String text = longText(128 * 1024, true); + + { + Ogg::Speex::File f(newname.c_str()); + f.tag()->setTitle(text); + f.save(); + } + { + Ogg::Speex::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(156330LL, f.length()); + CPPUNIT_ASSERT_EQUAL(23, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)80, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)131116, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)93, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL((size_t)93, f.packet(3).size()); + CPPUNIT_ASSERT_EQUAL(text, f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + + f.tag()->setTitle("ABCDE"); + f.save(); + } + { + Ogg::Speex::File f(newname.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT_EQUAL(24317LL, f.length()); + CPPUNIT_ASSERT_EQUAL(7, f.lastPageHeader()->pageSequenceNumber()); + CPPUNIT_ASSERT_EQUAL((size_t)80, f.packet(0).size()); + CPPUNIT_ASSERT_EQUAL((size_t)49, f.packet(1).size()); + CPPUNIT_ASSERT_EQUAL((size_t)93, f.packet(2).size()); + CPPUNIT_ASSERT_EQUAL((size_t)93, f.packet(3).size()); + CPPUNIT_ASSERT_EQUAL(String("ABCDE"), f.tag()->title()); + + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestSpeex); diff --git a/tests/taglib/test_string.cpp b/tests/taglib/test_string.cpp new file mode 100644 index 000000000..97ac8f8d4 --- /dev/null +++ b/tests/taglib/test_string.cpp @@ -0,0 +1,362 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 + +#include "tstring.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestString : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestString); + CPPUNIT_TEST(testString); + CPPUNIT_TEST(testRfind); + CPPUNIT_TEST(testUTF16Encode); + CPPUNIT_TEST(testUTF16Decode); + CPPUNIT_TEST(testUTF16DecodeInvalidBOM); + CPPUNIT_TEST(testUTF16DecodeEmptyWithBOM); + CPPUNIT_TEST(testSurrogatePair); + CPPUNIT_TEST(testAppendCharDetach); + CPPUNIT_TEST(testAppendStringDetach); + CPPUNIT_TEST(testToInt); + CPPUNIT_TEST(testFromInt); + CPPUNIT_TEST(testSubstr); + CPPUNIT_TEST(testNewline); + CPPUNIT_TEST(testUpper); + CPPUNIT_TEST(testEncodeNonLatin1); + CPPUNIT_TEST(testEncodeEmpty); + CPPUNIT_TEST(testEncodeNonBMP); + CPPUNIT_TEST(testIterator); + CPPUNIT_TEST(testInvalidUTF8); + CPPUNIT_TEST_SUITE_END(); + + public: + void testString() { + // Needs to know the system byte order for some Unicode tests. + bool littleEndian; + { + union { + int i; + char c; + } u; + + u.i = 1; + littleEndian = (u.c == 1) ? true : false; + } + + String s = "taglib string"; + ByteVector v = "taglib string"; + CPPUNIT_ASSERT(v == s.data(String::Latin1)); + + char str[] = "taglib string"; + CPPUNIT_ASSERT(strcmp(s.toCString(), str) == 0); + + s.clear(); + CPPUNIT_ASSERT(s.isEmpty()); + + String unicode("José Carlos", String::UTF8); + CPPUNIT_ASSERT(strcmp(unicode.toCString(), "Jos\xe9 Carlos") == 0); + + String latin = "Jos\xe9 Carlos"; + CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0); + + String c; + c = "1"; + CPPUNIT_ASSERT(c == L"1"); + + c = L'\u4E00'; + CPPUNIT_ASSERT(c == L"\u4E00"); + + String unicode2(unicode.to8Bit(true), String::UTF8); + CPPUNIT_ASSERT(unicode == unicode2); + + String unicode3(L"\u65E5\u672C\u8A9E"); + CPPUNIT_ASSERT(*(unicode3.toCWString() + 1) == L'\u672C'); + + String unicode4(L"\u65e5\u672c\u8a9e"); + CPPUNIT_ASSERT(unicode4[1] == L'\u672c'); + + String unicode5(L"\u65e5\u672c\u8a9e", String::UTF16BE); + CPPUNIT_ASSERT(unicode5[1] == (littleEndian ? L'\u2c67' : L'\u672c')); + + String unicode6(L"\u65e5\u672c\u8a9e", String::UTF16LE); + CPPUNIT_ASSERT(unicode6[1] == (littleEndian ? L'\u672c' : L'\u2c67')); + + CPPUNIT_ASSERT(String(" foo ").stripWhiteSpace() == String("foo")); + CPPUNIT_ASSERT(String("foo ").stripWhiteSpace() == String("foo")); + CPPUNIT_ASSERT(String(" foo").stripWhiteSpace() == String("foo")); + CPPUNIT_ASSERT(String("foo").stripWhiteSpace() == String("foo")); + CPPUNIT_ASSERT(String("f o o").stripWhiteSpace() == String("f o o")); + CPPUNIT_ASSERT(String(" f o o ").stripWhiteSpace() == String("f o o")); + + CPPUNIT_ASSERT(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0); + CPPUNIT_ASSERT(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0); + } + + void testUTF16Encode() { + String a("foo"); + ByteVector b("\0f\0o\0o", 6); + ByteVector c("f\0o\0o\0", 6); + ByteVector d("\377\376f\0o\0o\0", 8); + CPPUNIT_ASSERT(a.data(String::UTF16BE) != a.data(String::UTF16LE)); + CPPUNIT_ASSERT(b == a.data(String::UTF16BE)); + CPPUNIT_ASSERT(c == a.data(String::UTF16LE)); + CPPUNIT_ASSERT_EQUAL(d, a.data(String::UTF16)); + } + + void testUTF16Decode() { + String a("foo"); + ByteVector b("\0f\0o\0o", 6); + ByteVector c("f\0o\0o\0", 6); + ByteVector d("\377\376f\0o\0o\0", 8); + CPPUNIT_ASSERT_EQUAL(a, String(b, String::UTF16BE)); + CPPUNIT_ASSERT_EQUAL(a, String(c, String::UTF16LE)); + CPPUNIT_ASSERT_EQUAL(a, String(d, String::UTF16)); + } + + // this test is expected to print "TagLib: String::copyFromUTF16() - + // Invalid UTF16 string." on the console 3 times + void testUTF16DecodeInvalidBOM() { + ByteVector b(" ", 1); + ByteVector c(" ", 2); + ByteVector d(" \0f\0o\0o", 8); + CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16)); + CPPUNIT_ASSERT_EQUAL(String(), String(c, String::UTF16)); + CPPUNIT_ASSERT_EQUAL(String(), String(d, String::UTF16)); + } + + void testUTF16DecodeEmptyWithBOM() { + ByteVector a("\377\376", 2); + ByteVector b("\376\377", 2); + CPPUNIT_ASSERT_EQUAL(String(), String(a, String::UTF16)); + CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16)); + } + + void testSurrogatePair() { + // Make sure that a surrogate pair is converted into single UTF-8 char + // and vice versa. + + const ByteVector v1("\xff\xfe\x42\xd8\xb7\xdf\xce\x91\x4b\x5c"); + const ByteVector v2("\xf0\xa0\xae\xb7\xe9\x87\x8e\xe5\xb1\x8b"); + + const String s1(v1, String::UTF16); + CPPUNIT_ASSERT_EQUAL(s1.data(String::UTF8), v2); + + const String s2(v2, String::UTF8); + CPPUNIT_ASSERT_EQUAL(s2.data(String::UTF16), v1); + + const ByteVector v3("\xfe\xff\xd8\x01\x30\x42"); + CPPUNIT_ASSERT(String(v3, String::UTF16).data(String::UTF8).isEmpty()); + + const ByteVector v4("\xfe\xff\x30\x42\xdc\x01"); + CPPUNIT_ASSERT(String(v4, String::UTF16).data(String::UTF8).isEmpty()); + + const ByteVector v5("\xfe\xff\xdc\x01\xd8\x01"); + CPPUNIT_ASSERT(String(v5, String::UTF16).data(String::UTF8).isEmpty()); + } + + void testAppendStringDetach() { + String a("abc"); + String b = a; + String c = a; + + b += "def"; + c += L"def"; + + CPPUNIT_ASSERT_EQUAL(String("abc"), a); + CPPUNIT_ASSERT_EQUAL(String("abcdef"), b); + CPPUNIT_ASSERT_EQUAL(String("abcdef"), c); + } + + void testAppendCharDetach() { + String a("abc"); + String b = a; + String c = a; + + b += 'd'; + c += L'd'; + + CPPUNIT_ASSERT_EQUAL(String("abc"), a); + CPPUNIT_ASSERT_EQUAL(String("abcd"), b); + CPPUNIT_ASSERT_EQUAL(String("abcd"), c); + } + + void testRfind() { + CPPUNIT_ASSERT_EQUAL(String::npos(), String("foo.bar").rfind(".", 0)); + CPPUNIT_ASSERT_EQUAL(String::npos(), String("foo.bar").rfind(".", 1)); + CPPUNIT_ASSERT_EQUAL(String::npos(), String("foo.bar").rfind(".", 2)); + CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 3)); + CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 4)); + CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 5)); + CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 6)); + CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 7)); + CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".")); + } + + void testToInt() { + bool ok; + CPPUNIT_ASSERT_EQUAL(String("123").toInt(&ok), 123); + CPPUNIT_ASSERT_EQUAL(ok, true); + + CPPUNIT_ASSERT_EQUAL(String("-123").toInt(&ok), -123); + CPPUNIT_ASSERT_EQUAL(ok, true); + + CPPUNIT_ASSERT_EQUAL(String("123aa").toInt(&ok), 123); + CPPUNIT_ASSERT_EQUAL(ok, false); + + CPPUNIT_ASSERT_EQUAL(String("-123aa").toInt(&ok), -123); + CPPUNIT_ASSERT_EQUAL(ok, false); + + CPPUNIT_ASSERT_EQUAL(String("abc").toInt(&ok), 0); + CPPUNIT_ASSERT_EQUAL(ok, false); + + CPPUNIT_ASSERT_EQUAL(String("1x").toInt(&ok), 1); + CPPUNIT_ASSERT_EQUAL(ok, false); + + CPPUNIT_ASSERT_EQUAL(String("").toInt(&ok), 0); + CPPUNIT_ASSERT_EQUAL(ok, false); + + CPPUNIT_ASSERT_EQUAL(String("-").toInt(&ok), 0); + CPPUNIT_ASSERT_EQUAL(ok, false); + + String("9999999999").toInt(&ok); + CPPUNIT_ASSERT_EQUAL(ok, false); + + CPPUNIT_ASSERT_EQUAL(String("0000").toInt(), 0); + CPPUNIT_ASSERT_EQUAL(String("0001").toInt(), 1); + + String("2147483648").toInt(&ok); + CPPUNIT_ASSERT_EQUAL(ok, false); + + String("-2147483649").toInt(&ok); + CPPUNIT_ASSERT_EQUAL(ok, false); + } + + void testFromInt() { + CPPUNIT_ASSERT_EQUAL(String::number(0), String("0")); + CPPUNIT_ASSERT_EQUAL(String::number(12345678), String("12345678")); + CPPUNIT_ASSERT_EQUAL(String::number(-12345678), String("-12345678")); + } + + void testSubstr() { + CPPUNIT_ASSERT_EQUAL(String("01"), String("0123456").substr(0, 2)); + CPPUNIT_ASSERT_EQUAL(String("12"), String("0123456").substr(1, 2)); + CPPUNIT_ASSERT_EQUAL(String("123456"), String("0123456").substr(1, 200)); + CPPUNIT_ASSERT_EQUAL(String("0123456"), String("0123456").substr(0, 7)); + CPPUNIT_ASSERT_EQUAL(String("0123456"), String("0123456").substr(0, 200)); + } + + void testNewline() { + ByteVector cr("abc\x0dxyz", 7); + ByteVector lf("abc\x0axyz", 7); + ByteVector crlf("abc\x0d\x0axyz", 8); + + CPPUNIT_ASSERT_EQUAL((size_t)7, String(cr).size()); + CPPUNIT_ASSERT_EQUAL((size_t)7, String(lf).size()); + CPPUNIT_ASSERT_EQUAL((size_t)8, String(crlf).size()); + + CPPUNIT_ASSERT_EQUAL(L'\x0d', String(cr)[3]); + CPPUNIT_ASSERT_EQUAL(L'\x0a', String(lf)[3]); + CPPUNIT_ASSERT_EQUAL(L'\x0d', String(crlf)[3]); + CPPUNIT_ASSERT_EQUAL(L'\x0a', String(crlf)[4]); + } + + void testUpper() { + String s1 = "tagLIB 012 strING"; + String s2 = s1.upper(); + CPPUNIT_ASSERT_EQUAL(String("tagLIB 012 strING"), s1); + CPPUNIT_ASSERT_EQUAL(String("TAGLIB 012 STRING"), s2); + } + + void testEncodeNonLatin1() { + const String jpn(L"\u65E5\u672C\u8A9E"); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xE5\x2C\x9E"), jpn.data(String::Latin1)); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"), jpn.data(String::UTF8)); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xFF\xFE\xE5\x65\x2C\x67\x9E\x8A"), jpn.data(String::UTF16)); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xE5\x65\x2C\x67\x9E\x8A"), jpn.data(String::UTF16LE)); + CPPUNIT_ASSERT_EQUAL(ByteVector("\x65\xE5\x67\x2C\x8A\x9E"), jpn.data(String::UTF16BE)); + CPPUNIT_ASSERT_EQUAL(std::string("\xE5\x2C\x9E"), jpn.to8Bit(false)); + CPPUNIT_ASSERT_EQUAL(std::string("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"), jpn.to8Bit(true)); + } + + void testEncodeEmpty() { + const String empty; + CPPUNIT_ASSERT(empty.data(String::Latin1).isEmpty()); + CPPUNIT_ASSERT(empty.data(String::UTF8).isEmpty()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xFF\xFE"), empty.data(String::UTF16)); + CPPUNIT_ASSERT(empty.data(String::UTF16LE).isEmpty()); + CPPUNIT_ASSERT(empty.data(String::UTF16BE).isEmpty()); + CPPUNIT_ASSERT(empty.to8Bit(false).empty()); + CPPUNIT_ASSERT(empty.to8Bit(true).empty()); + } + + void testEncodeNonBMP() { + const ByteVector a("\xFF\xFE\x3C\xD8\x50\xDD\x40\xD8\xF5\xDC\x3C\xD8\x00\xDE", 14); + const ByteVector b("\xF0\x9F\x85\x90\xF0\xA0\x83\xB5\xF0\x9F\x88\x80"); + CPPUNIT_ASSERT_EQUAL(b, String(a, String::UTF16).data(String::UTF8)); + } + + void testIterator() { + String s1 = "taglib string"; + String s2 = s1; + + String::Iterator it1 = s1.begin(); + String::Iterator it2 = s2.begin(); + + CPPUNIT_ASSERT_EQUAL(L't', *it1); + CPPUNIT_ASSERT_EQUAL(L't', *it2); + + std::advance(it1, 4); + std::advance(it2, 4); + *it2 = L'I'; + CPPUNIT_ASSERT_EQUAL(L'i', *it1); + CPPUNIT_ASSERT_EQUAL(L'I', *it2); + } + + void testInvalidUTF8() { + CPPUNIT_ASSERT_EQUAL(String("/"), String(ByteVector("\x2F"), String::UTF8)); + CPPUNIT_ASSERT(String(ByteVector("\xC0\xAF"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xE0\x80\xAF"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xF0\x80\x80\xAF"), String::UTF8).isEmpty()); + + CPPUNIT_ASSERT(String(ByteVector("\xF8\x80\x80\x80\x80"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xFC\x80\x80\x80\x80\x80"), String::UTF8).isEmpty()); + + CPPUNIT_ASSERT(String(ByteVector("\xC2"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xE0\x80"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xF0\x80\x80"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xF8\x80\x80\x80"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xFC\x80\x80\x80\x80"), String::UTF8).isEmpty()); + + CPPUNIT_ASSERT(String('\x80', String::UTF8).isEmpty()); + + CPPUNIT_ASSERT(String(ByteVector("\xED\xA0\x80\xED\xB0\x80"), String::UTF8).isEmpty()); + CPPUNIT_ASSERT(String(ByteVector("\xED\xB0\x80\xED\xA0\x80"), String::UTF8).isEmpty()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestString); diff --git a/tests/taglib/test_synchdata.cpp b/tests/taglib/test_synchdata.cpp new file mode 100644 index 000000000..e4bea0da2 --- /dev/null +++ b/tests/taglib/test_synchdata.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 "id3v2synchdata.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestID3v2SynchData : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestID3v2SynchData); + CPPUNIT_TEST(test1); + CPPUNIT_TEST(test2); + CPPUNIT_TEST(test3); + CPPUNIT_TEST(testToUIntBroken); + CPPUNIT_TEST(testToUIntBrokenAndTooLarge); + CPPUNIT_TEST(testDecode1); + CPPUNIT_TEST(testDecode2); + CPPUNIT_TEST(testDecode3); + CPPUNIT_TEST(testDecode4); + CPPUNIT_TEST_SUITE_END(); + + public: + void test1() { + char data[] = { 0, 0, 0, 127 }; + ByteVector v(data, 4); + + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), (unsigned int)127); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(127), v); + } + + void test2() { + char data[] = { 0, 0, 1, 0 }; + ByteVector v(data, 4); + + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), (unsigned int)128); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(128), v); + } + + void test3() { + char data[] = { 0, 0, 1, 1 }; + ByteVector v(data, 4); + + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), (unsigned int)129); + CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(129), v); + } + + void testToUIntBroken() { + char data[] = { 0, 0, 0, (char)-1 }; + char data2[] = { 0, 0, (char)-1, (char)-1 }; + + CPPUNIT_ASSERT_EQUAL((unsigned int)255, ID3v2::SynchData::toUInt(ByteVector(data, 4))); + CPPUNIT_ASSERT_EQUAL((unsigned int)65535, ID3v2::SynchData::toUInt(ByteVector(data2, 4))); + } + + void testToUIntBrokenAndTooLarge() { + char data[] = { 0, 0, 0, (char)-1, 0 }; + ByteVector v(data, 5); + + CPPUNIT_ASSERT_EQUAL((unsigned int)255, ID3v2::SynchData::toUInt(v)); + } + + void testDecode1() { + ByteVector a("\xff\x00\x00", 3); + a = ID3v2::SynchData::decode(a); + CPPUNIT_ASSERT_EQUAL((size_t)2, a.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x00", 2), a); + } + + void testDecode2() { + ByteVector a("\xff\x44", 2); + a = ID3v2::SynchData::decode(a); + CPPUNIT_ASSERT_EQUAL((size_t)2, a.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x44", 2), a); + } + + void testDecode3() { + ByteVector a("\xff\xff\x00", 3); + a = ID3v2::SynchData::decode(a); + CPPUNIT_ASSERT_EQUAL((size_t)2, a.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\xff", 2), a); + } + + void testDecode4() { + ByteVector a("\xff\xff\xff", 3); + a = ID3v2::SynchData::decode(a); + CPPUNIT_ASSERT_EQUAL((size_t)3, a.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\xff\xff", 3), a); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2SynchData); diff --git a/tests/taglib/test_trueaudio.cpp b/tests/taglib/test_trueaudio.cpp new file mode 100644 index 000000000..bfb01c702 --- /dev/null +++ b/tests/taglib/test_trueaudio.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "id3v1tag.h" +#include "id3v2tag.h" +#include "tpropertymap.h" +#include "trueaudiofile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestTrueAudio : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestTrueAudio); + CPPUNIT_TEST(testReadPropertiesWithoutID3v2); + CPPUNIT_TEST(testReadPropertiesWithTags); + CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST_SUITE_END(); + + public: + void testReadPropertiesWithoutID3v2() { + TrueAudio::File f(TEST_FILE_PATH_C("empty.tta")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(173, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(162496U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->ttaVersion()); + } + + void testReadPropertiesWithTags() { + TrueAudio::File f(TEST_FILE_PATH_C("tagged.tta")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(173, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(162496U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->ttaVersion()); + } + + void testStripAndProperties() { + ScopedFileCopy copy("empty", ".tta"); + + { + TrueAudio::File f(copy.fileName().c_str()); + f.ID3v2Tag(true)->setTitle("ID3v2"); + f.ID3v1Tag(true)->setTitle("ID3v1"); + f.save(); + } + { + TrueAudio::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("ID3v2"), f.properties()["TITLE"].front()); + f.strip(TrueAudio::File::ID3v2); + CPPUNIT_ASSERT_EQUAL(String("ID3v1"), f.properties()["TITLE"].front()); + f.strip(TrueAudio::File::ID3v1); + CPPUNIT_ASSERT(f.properties().isEmpty()); + } + } + + void testRepeatedSave() { + ScopedFileCopy copy("empty", ".tta"); + + { + TrueAudio::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + + f.ID3v2Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.save(); + + f.ID3v2Tag()->setTitle("0"); + f.save(); + + f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.ID3v2Tag()->setTitle("01234 56789 ABCDE FGHIJ 01234 56789 ABCDE FGHIJ 01234 56789"); + f.save(); + } + { + TrueAudio::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestTrueAudio); diff --git a/tests/taglib/test_wav.cpp b/tests/taglib/test_wav.cpp new file mode 100644 index 000000000..8e232a25c --- /dev/null +++ b/tests/taglib/test_wav.cpp @@ -0,0 +1,295 @@ +/*************************************************************************** + copyright : (C) 2010 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "id3v2tag.h" +#include "infotag.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "wavfile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestWAV : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestWAV); + CPPUNIT_TEST(testPCMProperties); + CPPUNIT_TEST(testALAWProperties); + CPPUNIT_TEST(testFloatProperties); + CPPUNIT_TEST(testZeroSizeDataChunk); + CPPUNIT_TEST(testID3v2Tag); + CPPUNIT_TEST(testSaveID3v23); + CPPUNIT_TEST(testInfoTag); + CPPUNIT_TEST(testStripTags); + CPPUNIT_TEST(testDuplicateTags); + CPPUNIT_TEST(testFuzzedFile1); + CPPUNIT_TEST(testFuzzedFile2); + CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testPCMWithFactChunk); + CPPUNIT_TEST_SUITE_END(); + + public: + void testPCMProperties() { + RIFF::WAV::File f(TEST_FILE_PATH_C("empty.wav")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3675, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(32, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(1000, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(3675U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->format()); + } + + void testALAWProperties() { + RIFF::WAV::File f(TEST_FILE_PATH_C("alaw.wav")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3550, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(128, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(8000, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(8, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(28400U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(6, f.audioProperties()->format()); + } + + void testFloatProperties() { + RIFF::WAV::File f(TEST_FILE_PATH_C("float64.wav")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(97, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(5645, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(4281U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->format()); + } + + void testZeroSizeDataChunk() { + RIFF::WAV::File f(TEST_FILE_PATH_C("zero-size-chunk.wav")); + CPPUNIT_ASSERT(!f.isValid()); + } + + void testID3v2Tag() { + ScopedFileCopy copy("empty", ".wav"); + string filename = copy.fileName(); + + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + + f.ID3v2Tag()->setTitle(L"Title"); + f.ID3v2Tag()->setArtist(L"Artist"); + f.save(); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String(L"Title"), f.ID3v2Tag()->title()); + CPPUNIT_ASSERT_EQUAL(String(L"Artist"), f.ID3v2Tag()->artist()); + + f.ID3v2Tag()->setTitle(L""); + f.ID3v2Tag()->setArtist(L""); + f.save(); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String(L""), f.ID3v2Tag()->title()); + CPPUNIT_ASSERT_EQUAL(String(L""), f.ID3v2Tag()->artist()); + } + } + + void testSaveID3v23() { + ScopedFileCopy copy("empty", ".wav"); + string newname = copy.fileName(); + + String xxx = ByteVector(254, 'X'); + { + RIFF::WAV::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); + + f.tag()->setTitle(xxx); + f.tag()->setArtist("Artist A"); + f.save(RIFF::WAV::File::AllTags, File::StripOthers, ID3v2::v3); + CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); + } + { + RIFF::WAV::File f2(newname.c_str()); + CPPUNIT_ASSERT_EQUAL((unsigned int)3, f2.ID3v2Tag()->header()->majorVersion()); + CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); + CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); + } + } + + void testInfoTag() { + ScopedFileCopy copy("empty", ".wav"); + string filename = copy.fileName(); + + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasInfoTag()); + + f.InfoTag()->setTitle(L"Title"); + f.InfoTag()->setArtist(L"Artist"); + f.save(); + CPPUNIT_ASSERT(f.hasInfoTag()); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasInfoTag()); + CPPUNIT_ASSERT_EQUAL(String(L"Title"), f.InfoTag()->title()); + CPPUNIT_ASSERT_EQUAL(String(L"Artist"), f.InfoTag()->artist()); + + f.InfoTag()->setTitle(L""); + f.InfoTag()->setArtist(L""); + f.save(); + CPPUNIT_ASSERT(!f.hasInfoTag()); + } + + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasInfoTag()); + CPPUNIT_ASSERT_EQUAL(String(L""), f.InfoTag()->title()); + CPPUNIT_ASSERT_EQUAL(String(L""), f.InfoTag()->artist()); + } + } + + void testStripTags() { + ScopedFileCopy copy("empty", ".wav"); + string filename = copy.fileName(); + + { + RIFF::WAV::File f(filename.c_str()); + f.ID3v2Tag()->setTitle("test title"); + f.InfoTag()->setTitle("test title"); + f.save(); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT(f.hasInfoTag()); + f.save(RIFF::WAV::File::ID3v2, File::StripOthers); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT(!f.hasInfoTag()); + f.ID3v2Tag()->setTitle("test title"); + f.InfoTag()->setTitle("test title"); + f.save(); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT(f.hasInfoTag()); + f.save(RIFF::WAV::File::Info, File::StripOthers); + } + { + RIFF::WAV::File f(filename.c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + CPPUNIT_ASSERT(f.hasInfoTag()); + } + } + + void testDuplicateTags() { + ScopedFileCopy copy("duplicate_tags", ".wav"); + + RIFF::WAV::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(17052LL, f.length()); + + // duplicate_tags.wav has duplicate ID3v2/INFO tags. + // title() returns "Title2" if can't skip the second tag. + + CPPUNIT_ASSERT(f.hasID3v2Tag()); + CPPUNIT_ASSERT_EQUAL(String("Title1"), f.ID3v2Tag()->title()); + + CPPUNIT_ASSERT(f.hasInfoTag()); + CPPUNIT_ASSERT_EQUAL(String("Title1"), f.InfoTag()->title()); + + f.save(); + CPPUNIT_ASSERT_EQUAL(15898LL, f.length()); + CPPUNIT_ASSERT_EQUAL(-1LL, f.find("Title2")); + } + + void testFuzzedFile1() { + RIFF::WAV::File f1(TEST_FILE_PATH_C("infloop.wav")); + CPPUNIT_ASSERT(!f1.isValid()); + } + + void testFuzzedFile2() { + RIFF::WAV::File f2(TEST_FILE_PATH_C("segfault.wav")); + CPPUNIT_ASSERT(f2.isValid()); + } + + void testStripAndProperties() { + ScopedFileCopy copy("empty", ".wav"); + + { + RIFF::WAV::File f(copy.fileName().c_str()); + f.ID3v2Tag()->setTitle("ID3v2"); + f.InfoTag()->setTitle("INFO"); + f.save(); + } + { + RIFF::WAV::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("ID3v2"), f.properties()["TITLE"].front()); + f.strip(RIFF::WAV::File::ID3v2); + CPPUNIT_ASSERT_EQUAL(String("INFO"), f.properties()["TITLE"].front()); + f.strip(RIFF::WAV::File::Info); + CPPUNIT_ASSERT(f.properties().isEmpty()); + } + } + + void testPCMWithFactChunk() { + RIFF::WAV::File f(TEST_FILE_PATH_C("pcm_with_fact_chunk.wav")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3675, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(32, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(1000, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(3675U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->format()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV); diff --git a/tests/taglib/test_wavpack.cpp b/tests/taglib/test_wavpack.cpp new file mode 100644 index 000000000..cbe7c49b1 --- /dev/null +++ b/tests/taglib/test_wavpack.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + copyright : (C) 2010 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include + +#include "apetag.h" +#include "id3v1tag.h" +#include "tbytevectorlist.h" +#include "tpropertymap.h" +#include "wavpackfile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestWavPack : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestWavPack); + CPPUNIT_TEST(testNoLengthProperties); + CPPUNIT_TEST(testMultiChannelProperties); + CPPUNIT_TEST(testTaggedProperties); + CPPUNIT_TEST(testFuzzedFile); + CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testRepeatedSave); + CPPUNIT_TEST_SUITE_END(); + + public: + void testNoLengthProperties() { + WavPack::File f(TEST_FILE_PATH_C("no_length.wv")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3705, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(true, f.audioProperties()->isLossless()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(163392U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1031, f.audioProperties()->version()); + } + + void testMultiChannelProperties() { + WavPack::File f(TEST_FILE_PATH_C("four_channels.wv")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3833, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(112, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isLossless()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(169031U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1031, f.audioProperties()->version()); + } + + void testTaggedProperties() { + WavPack::File f(TEST_FILE_PATH_C("tagged.wv")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3550, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(172, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isLossless()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(156556U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1031, f.audioProperties()->version()); + } + + void testFuzzedFile() { + WavPack::File f(TEST_FILE_PATH_C("infloop.wv")); + CPPUNIT_ASSERT(f.isValid()); + } + + void testStripAndProperties() { + ScopedFileCopy copy("click", ".wv"); + + { + WavPack::File f(copy.fileName().c_str()); + f.APETag(true)->setTitle("APE"); + f.ID3v1Tag(true)->setTitle("ID3v1"); + f.save(); + } + { + WavPack::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT_EQUAL(String("APE"), f.properties()["TITLE"].front()); + f.strip(WavPack::File::APE); + CPPUNIT_ASSERT_EQUAL(String("ID3v1"), f.properties()["TITLE"].front()); + f.strip(WavPack::File::ID3v1); + CPPUNIT_ASSERT(f.properties().isEmpty()); + } + } + + void testRepeatedSave() { + ScopedFileCopy copy("click", ".wv"); + + { + WavPack::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(!f.hasAPETag()); + CPPUNIT_ASSERT(!f.hasID3v1Tag()); + + f.APETag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.save(); + + f.APETag()->setTitle("0"); + f.save(); + + f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ"); + f.APETag()->setTitle("01234 56789 ABCDE FGHIJ 01234 56789 ABCDE FGHIJ 01234 56789"); + f.save(); + } + { + WavPack::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.hasAPETag()); + CPPUNIT_ASSERT(f.hasID3v1Tag()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestWavPack); diff --git a/tests/taglib/test_xiphcomment.cpp b/tests/taglib/test_xiphcomment.cpp new file mode 100644 index 000000000..921478c21 --- /dev/null +++ b/tests/taglib/test_xiphcomment.cpp @@ -0,0 +1,209 @@ +/*************************************************************************** + copyright : (C) 2009 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include +#include "xiphcomment.h" +#include "vorbisfile.h" +#include "tpropertymap.h" +#include "tdebug.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +class TestXiphComment : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestXiphComment); + CPPUNIT_TEST(testYear); + CPPUNIT_TEST(testSetYear); + CPPUNIT_TEST(testTrack); + CPPUNIT_TEST(testSetTrack); + CPPUNIT_TEST(testInvalidKeys1); + CPPUNIT_TEST(testInvalidKeys2); + CPPUNIT_TEST(testClearComment); + CPPUNIT_TEST(testRemoveFields); + CPPUNIT_TEST(testPicture); + CPPUNIT_TEST(testLowercaseFields); + CPPUNIT_TEST_SUITE_END(); + + public: + void testYear() { + Ogg::XiphComment cmt; + CPPUNIT_ASSERT_EQUAL((unsigned int)0, cmt.year()); + cmt.addField("YEAR", "2009"); + CPPUNIT_ASSERT_EQUAL((unsigned int)2009, cmt.year()); + cmt.addField("DATE", "2008"); + CPPUNIT_ASSERT_EQUAL((unsigned int)2008, cmt.year()); + } + + void testSetYear() { + Ogg::XiphComment cmt; + cmt.addField("YEAR", "2009"); + cmt.addField("DATE", "2008"); + cmt.setYear(1995); + CPPUNIT_ASSERT(cmt.fieldListMap()["YEAR"].isEmpty()); + CPPUNIT_ASSERT_EQUAL(String("1995"), cmt.fieldListMap()["DATE"].front()); + } + + void testTrack() { + Ogg::XiphComment cmt; + CPPUNIT_ASSERT_EQUAL((unsigned int)0, cmt.track()); + cmt.addField("TRACKNUM", "7"); + CPPUNIT_ASSERT_EQUAL((unsigned int)7, cmt.track()); + cmt.addField("TRACKNUMBER", "8"); + CPPUNIT_ASSERT_EQUAL((unsigned int)8, cmt.track()); + } + + void testSetTrack() { + Ogg::XiphComment cmt; + cmt.addField("TRACKNUM", "7"); + cmt.addField("TRACKNUMBER", "8"); + cmt.setTrack(3); + CPPUNIT_ASSERT(cmt.fieldListMap()["TRACKNUM"].isEmpty()); + CPPUNIT_ASSERT_EQUAL(String("3"), cmt.fieldListMap()["TRACKNUMBER"].front()); + } + + void testInvalidKeys1() { + PropertyMap map; + map[""] = String("invalid key: empty string"); + map["A=B"] = String("invalid key: contains '='"); + map["A~B"] = String("invalid key: contains '~'"); + map["A\x7F" + "B"] = String("invalid key: contains '\x7F'"); + map[L"A\x3456" + "B"] = String("invalid key: Unicode"); + + Ogg::XiphComment cmt; + PropertyMap unsuccessful = cmt.setProperties(map); + CPPUNIT_ASSERT_EQUAL((size_t)5, unsuccessful.size()); + CPPUNIT_ASSERT(cmt.properties().isEmpty()); + } + + void testInvalidKeys2() { + Ogg::XiphComment cmt; + cmt.addField("", "invalid key: empty string"); + cmt.addField("A=B", "invalid key: contains '='"); + cmt.addField("A~B", "invalid key: contains '~'"); + cmt.addField("A\x7F" + "B", + "invalid key: contains '\x7F'"); + cmt.addField(L"A\x3456" + "B", + "invalid key: Unicode"); + CPPUNIT_ASSERT_EQUAL(0U, cmt.fieldCount()); + } + + void testClearComment() { + ScopedFileCopy copy("empty", ".ogg"); + + { + Ogg::Vorbis::File f(copy.fileName().c_str()); + f.tag()->addField("COMMENT", "Comment1"); + f.save(); + } + { + Ogg::Vorbis::File f(copy.fileName().c_str()); + f.tag()->setComment(""); + CPPUNIT_ASSERT_EQUAL(String(""), f.tag()->comment()); + } + } + + void testRemoveFields() { + Ogg::Vorbis::File f(TEST_FILE_PATH_C("empty.ogg")); + f.tag()->addField("title", "Title1"); + f.tag()->addField("Title", "Title1", false); + f.tag()->addField("titlE", "Title2", false); + f.tag()->addField("TITLE", "Title3", false); + f.tag()->addField("artist", "Artist1"); + f.tag()->addField("ARTIST", "Artist2", false); + CPPUNIT_ASSERT_EQUAL(String("Title1 Title1 Title2 Title3"), f.tag()->title()); + CPPUNIT_ASSERT_EQUAL(String("Artist1 Artist2"), f.tag()->artist()); + + f.tag()->removeFields("title", "Title1"); + CPPUNIT_ASSERT_EQUAL(String("Title2 Title3"), f.tag()->title()); + CPPUNIT_ASSERT_EQUAL(String("Artist1 Artist2"), f.tag()->artist()); + + f.tag()->removeFields("Artist"); + CPPUNIT_ASSERT_EQUAL(String("Title2 Title3"), f.tag()->title()); + CPPUNIT_ASSERT(f.tag()->artist().isEmpty()); + + f.tag()->removeAllFields(); + CPPUNIT_ASSERT(f.tag()->title().isEmpty()); + CPPUNIT_ASSERT(f.tag()->artist().isEmpty()); + CPPUNIT_ASSERT_EQUAL(String("Xiph.Org libVorbis I 20050304"), f.tag()->vendorID()); + } + + void testPicture() { + ScopedFileCopy copy("empty", ".ogg"); + string newname = copy.fileName(); + + { + Ogg::Vorbis::File f(newname.c_str()); + FLAC::Picture *newpic = new FLAC::Picture(); + newpic->setType(FLAC::Picture::BackCover); + newpic->setWidth(5); + newpic->setHeight(6); + newpic->setColorDepth(16); + newpic->setNumColors(7); + newpic->setMimeType("image/jpeg"); + newpic->setDescription("new image"); + newpic->setData("JPEG data"); + f.tag()->addPicture(newpic); + f.save(); + } + { + Ogg::Vorbis::File f(newname.c_str()); + List lst = f.tag()->pictureList(); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + CPPUNIT_ASSERT_EQUAL((int)5, lst[0]->width()); + CPPUNIT_ASSERT_EQUAL((int)6, lst[0]->height()); + CPPUNIT_ASSERT_EQUAL((int)16, lst[0]->colorDepth()); + CPPUNIT_ASSERT_EQUAL((int)7, lst[0]->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), lst[0]->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("new image"), lst[0]->description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), lst[0]->data()); + } + } + + void testLowercaseFields() { + const ScopedFileCopy copy("lowercase-fields", ".ogg"); + { + Ogg::Vorbis::File f(copy.fileName().c_str()); + List lst = f.tag()->pictureList(); + CPPUNIT_ASSERT_EQUAL(String("TEST TITLE"), f.tag()->title()); + CPPUNIT_ASSERT_EQUAL(String("TEST ARTIST"), f.tag()->artist()); + CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size()); + f.save(); + } + { + Ogg::Vorbis::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.find("METADATA_BLOCK_PICTURE") > 0); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestXiphComment); diff --git a/tests/taglib/test_xm.cpp b/tests/taglib/test_xm.cpp new file mode 100644 index 000000000..657d7e321 --- /dev/null +++ b/tests/taglib/test_xm.cpp @@ -0,0 +1,214 @@ +/*************************************************************************** + 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 * + * 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 "xmfile.h" +#include "utils.h" + +using namespace std; +using namespace Strawberry_TagLib::TagLib; + +static const String titleBefore("title of song"); +static const String titleAfter("changed title"); + +static const String trackerNameBefore("MilkyTracker "); +static const String trackerNameAfter("TagLib"); + +static const String commentBefore( + "Instrument names\n" + "are abused as\n" + "comments in\n" + "module file formats.\n" + "-+-+-+-+-+-+-+-+-+-+-+\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n" + "Sample\n" + "names\n" + "are sometimes\n" + "also abused as\n" + "comments."); + +static const String newCommentShort( + "Instrument names\n" + "are abused as\n" + "comments in\n" + "module file formats.\n" + "======================\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n" + "Sample names\n" + "are sometimes\n" + "also abused as\n" + "comments."); + +static const String newCommentLong( + "Instrument names\n" + "are abused as\n" + "comments in\n" + "module file formats.\n" + "======================\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n" + "Sample names\n" + "are sometimes\n" + "also abused as\n" + "comments.\n" + "\n\n\n\n\n\n\n" + "TEST"); + +static const String commentAfter( + "Instrument names\n" + "are abused as\n" + "comments in\n" + "module file formats.\n" + "======================\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n" + "Sample names\n" + "are sometimes\n" + "also abused as\n" + "comments.\n"); + +class TestXM : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestXM); + CPPUNIT_TEST(testReadTags); + CPPUNIT_TEST(testReadStrippedTags); + CPPUNIT_TEST(testWriteTagsShort); + CPPUNIT_TEST(testWriteTagsLong); + CPPUNIT_TEST_SUITE_END(); + + public: + void testReadTags() { + testRead(TEST_FILE_PATH_C("test.xm"), titleBefore, + commentBefore, trackerNameBefore); + } + + void testReadStrippedTags() { + XM::File file(TEST_FILE_PATH_C("stripped.xm")); + CPPUNIT_ASSERT(file.isValid()); + + XM::AudioProperties *p = file.audioProperties(); + Mod::Tag *t = file.tag(); + + CPPUNIT_ASSERT(nullptr != p); + CPPUNIT_ASSERT(nullptr != t); + + CPPUNIT_ASSERT_EQUAL(0, p->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); + CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); + CPPUNIT_ASSERT_EQUAL(8, p->channels()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->lengthInPatterns()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->version()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->restartPosition()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->patternCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->instrumentCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->flags()); + CPPUNIT_ASSERT_EQUAL((unsigned short)6, p->tempo()); + CPPUNIT_ASSERT_EQUAL((unsigned short)125, p->bpmSpeed()); + CPPUNIT_ASSERT_EQUAL(titleBefore, t->title()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); + CPPUNIT_ASSERT_EQUAL(String(), t->comment()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); + CPPUNIT_ASSERT_EQUAL(0U, t->year()); + CPPUNIT_ASSERT_EQUAL(0U, t->track()); + CPPUNIT_ASSERT_EQUAL(String(), t->trackerName()); + } + + void testWriteTagsShort() { + testWriteTags(newCommentShort); + } + + void testWriteTagsLong() { + testWriteTags(newCommentLong); + } + + private: + void testRead(FileName fileName, const String &title, + const String &comment, const String &trackerName) { + XM::File file(fileName); + + CPPUNIT_ASSERT(file.isValid()); + + XM::AudioProperties *p = file.audioProperties(); + Mod::Tag *t = file.tag(); + + CPPUNIT_ASSERT(nullptr != p); + CPPUNIT_ASSERT(nullptr != t); + + CPPUNIT_ASSERT_EQUAL(0, p->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); + CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); + CPPUNIT_ASSERT_EQUAL(8, p->channels()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->lengthInPatterns()); + CPPUNIT_ASSERT_EQUAL((unsigned short)260, p->version()); + CPPUNIT_ASSERT_EQUAL((unsigned short)0, p->restartPosition()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->patternCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)128, p->instrumentCount()); + CPPUNIT_ASSERT_EQUAL((unsigned short)1, p->flags()); + CPPUNIT_ASSERT_EQUAL((unsigned short)6, p->tempo()); + CPPUNIT_ASSERT_EQUAL((unsigned short)125, p->bpmSpeed()); + CPPUNIT_ASSERT_EQUAL(title, t->title()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); + CPPUNIT_ASSERT_EQUAL(comment, t->comment()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); + CPPUNIT_ASSERT_EQUAL(0U, t->year()); + CPPUNIT_ASSERT_EQUAL(0U, t->track()); + CPPUNIT_ASSERT_EQUAL(trackerName, t->trackerName()); + } + + void testWriteTags(const String &comment) { + ScopedFileCopy copy("test", ".xm"); + { + XM::File file(copy.fileName().c_str()); + CPPUNIT_ASSERT(file.tag() != nullptr); + file.tag()->setTitle(titleAfter); + file.tag()->setComment(comment); + file.tag()->setTrackerName(trackerNameAfter); + CPPUNIT_ASSERT(file.save()); + } + testRead(copy.fileName().c_str(), titleAfter, + commentAfter, trackerNameAfter); + CPPUNIT_ASSERT(fileEqual( + copy.fileName(), + TEST_FILE_PATH_C("changed.xm"))); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestXM); diff --git a/tests/taglib/utils.h b/tests/taglib/utils.h new file mode 100644 index 000000000..abdca6cc5 --- /dev/null +++ b/tests/taglib/utils.h @@ -0,0 +1,140 @@ +/*************************************************************************** + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ + +/*************************************************************************** + * 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/ * + ***************************************************************************/ + +#pragma once + +#include "taglib-config.h" + +#ifdef _WIN32 +# include +#else +# include +# include +# include +# include +#endif +#include +#include +#include +#include + +using namespace std; + +inline string testFilePath(const string &filename) { + return string(TESTS_DIR "data/") + filename; +} + +#define TEST_FILE_PATH_C(f) testFilePath(f).c_str() + +inline string copyFile(const string &filename, const string &ext) { + char testFileName[1024]; + +#ifdef _WIN32 + char tempDir[MAX_PATH + 1]; + GetTempPathA(sizeof(tempDir), tempDir); + wsprintfA(testFileName, "%s\\taglib-test%s", tempDir, ext.c_str()); +#else + snprintf(testFileName, sizeof(testFileName), "/%s/taglib-test%s", P_tmpdir, ext.c_str()); +#endif + + string sourceFileName = testFilePath(filename) + ext; + ifstream source(sourceFileName.c_str(), std::ios::binary); + ofstream destination(testFileName, std::ios::binary); + destination << source.rdbuf(); + return string(testFileName); +} + +inline void deleteFile(const string &filename) { + remove(filename.c_str()); +} + +inline bool fileEqual(const string &filename1, const string &filename2) { + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + ifstream stream1(filename1.c_str(), ios_base::in | ios_base::binary); + ifstream stream2(filename2.c_str(), ios_base::in | ios_base::binary); + + if (!stream1 && !stream2) return true; + if (!stream1 || !stream2) return false; + + for (;;) { + stream1.read(buf1, BUFSIZ); + stream2.read(buf2, BUFSIZ); + + streamsize n1 = stream1.gcount(); + streamsize n2 = stream2.gcount(); + + if (n1 != n2) return false; + + if (n1 == 0) break; + + if (memcmp(buf1, buf2, static_cast(n1)) != 0) return false; + } + + return stream1.good() == stream2.good(); +} + +#ifdef TAGLIB_STRING_H + +namespace Strawberry_TagLib { +namespace TagLib { + +inline String longText(size_t length, bool random = false) { + const wchar_t chars[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; + + std::wstring text(length, L'X'); + + if (random) { + for (size_t i = 0; i < length; ++i) + text[i] = chars[rand() % 53]; + } + + return String(text); +} +} // namespace TagLib +} // namespace Strawberry_TagLib + +#endif + +class ScopedFileCopy { + public: + ScopedFileCopy(const string &filename, const string &ext, bool deleteFile = true) : m_deleteFile(deleteFile), + m_filename(copyFile(filename, ext)) { + } + + ~ScopedFileCopy() { + if (m_deleteFile) + deleteFile(m_filename); + } + + string fileName() const { + return m_filename; + } + + private: + const bool m_deleteFile; + const string m_filename; +};