diff --git a/3rdparty/taglib/CMakeLists.txt b/3rdparty/taglib/CMakeLists.txt index 6aac92bdb..1ee3e8576 100644 --- a/3rdparty/taglib/CMakeLists.txt +++ b/3rdparty/taglib/CMakeLists.txt @@ -1,3 +1,5 @@ +cmake_minimum_required(VERSION 2.8.11) +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-delete-non-virtual-dtor") set(TAGLIB_SOVERSION_CURRENT 17) @@ -45,6 +47,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/s3m ${CMAKE_CURRENT_SOURCE_DIR}/it ${CMAKE_CURRENT_SOURCE_DIR}/xm + ${CMAKE_SOURCE_DIR}/3rdparty ) if(ZLIB_FOUND) @@ -53,10 +56,6 @@ elseif(HAVE_ZLIB_SOURCE) include_directories(${ZLIB_SOURCE}) endif() -if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC OR HAVE_BOOST_ZLIB) - include_directories(${Boost_INCLUDE_DIR}) -endif() - set(tag_HDRS tag.h fileref.h @@ -333,12 +332,6 @@ set(toolkit_SRCS toolkit/tzlib.cpp ) -if(NOT WIN32) - set(unicode_SRCS - toolkit/unicode.cpp - ) -endif() - if(HAVE_ZLIB_SOURCE) set(zlib_SRCS ${ZLIB_SOURCE}/adler32.c @@ -355,7 +348,7 @@ set(tag_LIB_SRCS ${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS} ${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS} ${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS} - ${unicode_SRCS} ${zlib_SRCS} + ${zlib_SRCS} tag.cpp tagunion.cpp fileref.cpp @@ -365,18 +358,10 @@ set(tag_LIB_SRCS add_library(tag STATIC ${tag_LIB_SRCS} ${tag_HDRS}) -if(ZLIB_FOUND) +if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE) target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() -if(HAVE_BOOST_ATOMIC) - target_link_libraries(tag ${Boost_ATOMIC_LIBRARY}) -endif() - -if(HAVE_BOOST_ZLIB) - target_link_libraries(tag ${Boost_IOSTREAMS_LIBRARY} ${Boost_ZLIB_LIBRARY}) -endif() - set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} diff --git a/3rdparty/taglib/ape/apefile.cpp b/3rdparty/taglib/ape/apefile.cpp index 9f298aaf4..a10c1f646 100644 --- a/3rdparty/taglib/ape/apefile.cpp +++ b/3rdparty/taglib/ape/apefile.cpp @@ -83,6 +83,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool APE::File::isSupported(IOStream *stream) +{ + // An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); + return (buffer.find("MAC ") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/ape/apefile.h b/3rdparty/taglib/ape/apefile.h index cfb19ff73..267778bae 100644 --- a/3rdparty/taglib/ape/apefile.h +++ b/3rdparty/taglib/ape/apefile.h @@ -211,6 +211,15 @@ namespace TagLib { */ bool hasID3v1Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as an APE + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/ape/apetag.cpp b/3rdparty/taglib/ape/apetag.cpp index 89ef8ff41..79e1d5cc7 100644 --- a/3rdparty/taglib/ape/apetag.cpp +++ b/3rdparty/taglib/ape/apetag.cpp @@ -47,23 +47,24 @@ using namespace APE; namespace { - bool isKeyValid(const char *key, size_t length) + const unsigned int MinKeyLength = 2; + const unsigned int MaxKeyLength = 255; + + bool isKeyValid(const ByteVector &key) { const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 }; - if(length < 2 || length > 255) - return false; - // only allow printable ASCII including space (32..126) - for(const char *p = key; p < key + length; ++p) { - const int c = static_cast(*p); + for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) { + const int c = static_cast(*it); if(c < 32 || c > 126) return false; } + const String upperKey = String(key).upper(); for(size_t i = 0; invalidKeys[i] != 0; ++i) { - if(Utils::equalsIgnoreCase(key, invalidKeys[i])) + if(upperKey == invalidKeys[i]) return false; } @@ -191,7 +192,7 @@ void APE::Tag::setGenre(const String &s) void APE::Tag::setYear(unsigned int i) { - if(i <= 0) + if(i == 0) removeItem("YEAR"); else addValue("YEAR", String::number(i), true); @@ -199,7 +200,7 @@ void APE::Tag::setYear(unsigned int i) void APE::Tag::setTrack(unsigned int i) { - if(i <= 0) + if(i == 0) removeItem("TRACK"); else addValue("TRACK", String::number(i), true); @@ -296,11 +297,10 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) bool APE::Tag::checkKey(const String &key) { - if(!key.isLatin1()) + if(key.size() < MinKeyLength || key.size() > MaxKeyLength) return false; - const std::string data = key.to8Bit(false); - return isKeyValid(data.c_str(), data.size()); + return isKeyValid(key.data(String::UTF8)); } APE::Footer *APE::Tag::footer() const @@ -419,7 +419,10 @@ void APE::Tag::parse(const ByteVector &data) const unsigned int keyLength = nullPos - pos - 8; const unsigned int valLegnth = data.toUInt(pos, false); - if(isKeyValid(&data[pos + 8], keyLength)){ + if(keyLength >= MinKeyLength + && keyLength <= MaxKeyLength + && isKeyValid(data.mid(pos + 8, keyLength))) + { APE::Item item; item.parse(data.mid(pos)); diff --git a/3rdparty/taglib/asf/asfattribute.cpp b/3rdparty/taglib/asf/asfattribute.cpp index 1e6ed7051..6faf7973b 100644 --- a/3rdparty/taglib/asf/asfattribute.cpp +++ b/3rdparty/taglib/asf/asfattribute.cpp @@ -36,20 +36,16 @@ using namespace TagLib; class ASF::Attribute::AttributePrivate : public RefCounter { public: - AttributePrivate() - : pictureValue(ASF::Picture::fromInvalid()), - stream(0), - language(0) {} + AttributePrivate() : + pictureValue(ASF::Picture::fromInvalid()), + numericValue(0), + stream(0), + language(0) {} AttributeTypes type; String stringValue; ByteVector byteVectorValue; ASF::Picture pictureValue; - union { - unsigned int intValue; - unsigned short shortValue; - unsigned long long longLongValue; - bool boolValue; - }; + unsigned long long numericValue; int stream; int language; }; @@ -95,28 +91,28 @@ ASF::Attribute::Attribute(unsigned int value) : d(new AttributePrivate()) { d->type = DWordType; - d->intValue = value; + d->numericValue = value; } ASF::Attribute::Attribute(unsigned long long value) : d(new AttributePrivate()) { d->type = QWordType; - d->longLongValue = value; + d->numericValue = value; } ASF::Attribute::Attribute(unsigned short value) : d(new AttributePrivate()) { d->type = WordType; - d->shortValue = value; + d->numericValue = value; } ASF::Attribute::Attribute(bool value) : d(new AttributePrivate()) { d->type = BoolType; - d->boolValue = value; + d->numericValue = value; } ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) @@ -157,22 +153,22 @@ ByteVector ASF::Attribute::toByteVector() const unsigned short ASF::Attribute::toBool() const { - return d->shortValue; + return d->numericValue ? 1 : 0; } unsigned short ASF::Attribute::toUShort() const { - return d->shortValue; + return static_cast(d->numericValue); } unsigned int ASF::Attribute::toUInt() const { - return d->intValue; + return static_cast(d->numericValue); } unsigned long long ASF::Attribute::toULongLong() const { - return d->longLongValue; + return static_cast(d->numericValue); } ASF::Picture ASF::Attribute::toPicture() const @@ -212,24 +208,24 @@ String ASF::Attribute::parse(ASF::File &f, int kind) switch(d->type) { case WordType: - d->shortValue = readWORD(&f); + d->numericValue = readWORD(&f); break; case BoolType: if(kind == 0) { - d->boolValue = (readDWORD(&f) == 1); + d->numericValue = (readDWORD(&f) != 0); } else { - d->boolValue = (readWORD(&f) == 1); + d->numericValue = (readWORD(&f) != 0); } break; case DWordType: - d->intValue = readDWORD(&f); + d->numericValue = readDWORD(&f); break; case QWordType: - d->longLongValue = readQWORD(&f); + d->numericValue = readQWORD(&f); break; case UnicodeType: @@ -280,24 +276,24 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const switch (d->type) { case WordType: - data.append(ByteVector::fromShort(d->shortValue, false)); + data.append(ByteVector::fromShort(toUShort(), false)); break; case BoolType: if(kind == 0) { - data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false)); + data.append(ByteVector::fromUInt(toBool(), false)); } else { - data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false)); + data.append(ByteVector::fromShort(toBool(), false)); } break; case DWordType: - data.append(ByteVector::fromUInt(d->intValue, false)); + data.append(ByteVector::fromUInt(toUInt(), false)); break; case QWordType: - data.append(ByteVector::fromLongLong(d->longLongValue, false)); + data.append(ByteVector::fromLongLong(toULongLong(), false)); break; case UnicodeType: diff --git a/3rdparty/taglib/asf/asfattribute.h b/3rdparty/taglib/asf/asfattribute.h index 64979216f..1738eb459 100644 --- a/3rdparty/taglib/asf/asfattribute.h +++ b/3rdparty/taglib/asf/asfattribute.h @@ -113,7 +113,7 @@ namespace TagLib /*! * Copies the contents of \a other into this item. */ - ASF::Attribute &operator=(const Attribute &other); + Attribute &operator=(const Attribute &other); /*! * Exchanges the content of the Attribute by the content of \a other. diff --git a/3rdparty/taglib/asf/asffile.cpp b/3rdparty/taglib/asf/asffile.cpp index 8f3952658..fd754803d 100644 --- a/3rdparty/taglib/asf/asffile.cpp +++ b/3rdparty/taglib/asf/asffile.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "asffile.h" #include "asftag.h" @@ -258,7 +259,6 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) { - file->d->contentDescriptionObject = this; const int titleLength = readWORD(file); const int artistLength = readWORD(file); const int copyrightLength = readWORD(file); @@ -299,7 +299,6 @@ ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() cons void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/) { - file->d->extendedContentDescriptionObject = this; int count = readWORD(file); while(count--) { ASF::Attribute attribute; @@ -323,7 +322,6 @@ ByteVector ASF::File::FilePrivate::MetadataObject::guid() const void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/) { - file->d->metadataObject = this; int count = readWORD(file); while(count--) { ASF::Attribute attribute; @@ -347,7 +345,6 @@ ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/) { - file->d->metadataLibraryObject = this; int count = readWORD(file); while(count--) { ASF::Attribute attribute; @@ -376,7 +373,6 @@ ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/) { - file->d->headerExtensionObject = this; file->seek(18, File::Current); long long dataSize = readDWORD(file); long long dataPos = 0; @@ -394,10 +390,12 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig } BaseObject *obj; if(guid == metadataGuid) { - obj = new MetadataObject(); + file->d->metadataObject = new MetadataObject(); + obj = file->d->metadataObject; } else if(guid == metadataLibraryGuid) { - obj = new MetadataLibraryObject(); + file->d->metadataLibraryObject = new MetadataLibraryObject(); + obj = file->d->metadataLibraryObject; } else { obj = new UnknownObject(guid); @@ -473,6 +471,18 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in } } +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool ASF::File::isSupported(IOStream *stream) +{ + // An ASF file has to start with the designated GUID. + + const ByteVector id = Utils::readHeader(stream, 16, false); + return (id == headerGuid); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -616,9 +626,8 @@ void ASF::File::read() if(!isValid()) return; - ByteVector guid = readBlock(16); - if(guid != headerGuid) { - debug("ASF: Not an ASF file."); + if(readBlock(16) != headerGuid) { + debug("ASF::File::read(): Not an ASF file."); setValid(false); return; } @@ -639,8 +648,10 @@ void ASF::File::read() } seek(2, Current); + FilePrivate::FilePropertiesObject *filePropertiesObject = 0; + FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0; for(int i = 0; i < numObjects; i++) { - guid = readBlock(16); + const ByteVector guid = readBlock(16); if(guid.size() != 16) { setValid(false); break; @@ -652,19 +663,24 @@ void ASF::File::read() } FilePrivate::BaseObject *obj; if(guid == filePropertiesGuid) { - obj = new FilePrivate::FilePropertiesObject(); + filePropertiesObject = new FilePrivate::FilePropertiesObject(); + obj = filePropertiesObject; } else if(guid == streamPropertiesGuid) { - obj = new FilePrivate::StreamPropertiesObject(); + streamPropertiesObject = new FilePrivate::StreamPropertiesObject(); + obj = streamPropertiesObject; } else if(guid == contentDescriptionGuid) { - obj = new FilePrivate::ContentDescriptionObject(); + d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject(); + obj = d->contentDescriptionObject; } else if(guid == extendedContentDescriptionGuid) { - obj = new FilePrivate::ExtendedContentDescriptionObject(); + d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject(); + obj = d->extendedContentDescriptionObject; } else if(guid == headerExtensionGuid) { - obj = new FilePrivate::HeaderExtensionObject(); + d->headerExtensionObject = new FilePrivate::HeaderExtensionObject(); + obj = d->headerExtensionObject; } else if(guid == codecListGuid) { obj = new FilePrivate::CodecListObject(); @@ -680,4 +696,10 @@ void ASF::File::read() obj->parse(this, size); d->objects.append(obj); } + + if(!filePropertiesObject || !streamPropertiesObject) { + debug("ASF::File::read(): Missing mandatory header objects."); + setValid(false); + return; + } } diff --git a/3rdparty/taglib/asf/asffile.h b/3rdparty/taglib/asf/asffile.h index b674da79c..05cf4ee2a 100644 --- a/3rdparty/taglib/asf/asffile.h +++ b/3rdparty/taglib/asf/asffile.h @@ -115,6 +115,15 @@ namespace TagLib { */ virtual bool save(); + /*! + * Returns whether or not the given \a stream can be opened as an ASF + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: void read(); diff --git a/3rdparty/taglib/asf/asftag.cpp b/3rdparty/taglib/asf/asftag.cpp index ed2dba522..20a946f0a 100644 --- a/3rdparty/taglib/asf/asftag.cpp +++ b/3rdparty/taglib/asf/asftag.cpp @@ -39,10 +39,10 @@ public: AttributeListMap attributeListMap; }; -ASF::Tag::Tag() -: TagLib::Tag() +ASF::Tag::Tag() : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; } ASF::Tag::~Tag() diff --git a/3rdparty/taglib/audioproperties.cpp b/3rdparty/taglib/audioproperties.cpp index 217d92870..c29051a64 100644 --- a/3rdparty/taglib/audioproperties.cpp +++ b/3rdparty/taglib/audioproperties.cpp @@ -43,6 +43,39 @@ using namespace TagLib; +// This macro is a workaround for the fact that we can't add virtual functions. +// Should be true virtual functions in taglib2. + +#define VIRTUAL_FUNCTION_WORKAROUND(function_name, default_value) \ + if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else if(dynamic_cast(this)) \ + return dynamic_cast(this)->function_name(); \ + else \ + return (default_value); + class AudioProperties::AudioPropertiesPrivate { @@ -59,98 +92,12 @@ AudioProperties::~AudioProperties() int AudioProperties::lengthInSeconds() const { - // This is an ugly workaround but we can't add a virtual function. - // Should be virtual in taglib2. - - if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if (dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInSeconds(); - - else - return 0; + VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0) } int AudioProperties::lengthInMilliseconds() const { - // This is an ugly workaround but we can't add a virtual function. - // Should be virtual in taglib2. - - if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else if(dynamic_cast(this)) - return dynamic_cast(this)->lengthInMilliseconds(); - - else - return 0; + VIRTUAL_FUNCTION_WORKAROUND(lengthInMilliseconds, 0) } //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/fileref.cpp b/3rdparty/taglib/fileref.cpp index 3a7f2c65e..935c371bd 100644 --- a/3rdparty/taglib/fileref.cpp +++ b/3rdparty/taglib/fileref.cpp @@ -28,6 +28,7 @@ ***************************************************************************/ #include +#include #include #include #include @@ -59,49 +60,14 @@ namespace typedef List ResolverList; ResolverList fileTypeResolvers; - // Templatized internal functions. T should be String or IOStream*. + // Detect the file type by user-defined resolvers. - template - FileName toFileName(T arg) - { - debug("FileRef::toFileName(): This version should never be called."); - return FileName(L""); - } - - template <> - FileName toFileName(IOStream *arg) - { - return arg->name(); - } - - template <> - FileName toFileName(FileName arg) - { - return arg; - } - - template - File *resolveFileType(T arg, bool readProperties, - AudioProperties::ReadStyle style) - { - debug("FileRef::resolveFileType(): This version should never be called."); - return 0; - } - - template <> - File *resolveFileType(IOStream *arg, bool readProperties, - AudioProperties::ReadStyle style) - { - return 0; - } - - template <> - File *resolveFileType(FileName arg, bool readProperties, - AudioProperties::ReadStyle style) + File *detectByResolvers(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) { ResolverList::ConstIterator it = fileTypeResolvers.begin(); for(; it != fileTypeResolvers.end(); ++it) { - File *file = (*it)->createFile(arg, readProperties, style); + File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); if(file) return file; } @@ -109,18 +75,15 @@ namespace return 0; } - template - File* createInternal(T arg, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) - { - File *file = resolveFileType(arg, readAudioProperties, audioPropertiesStyle); - if(file) - return file; + // Detect the file type based on the file extension. + File* detectByExtension(IOStream *stream, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { #ifdef _WIN32 - const String s = toFileName(arg).toString(); + const String s = stream->name().toString(); #else - const String s(toFileName(arg)); + const String s(stream->name()); #endif String ext; @@ -135,49 +98,163 @@ namespace if(ext.isEmpty()) return 0; + // .oga can be any audio in the Ogg container. So leave it to content-based detection. + if(ext == "MP3") - return new MPEG::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); if(ext == "OGG") - return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle); + return new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "FLAC") + return new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + if(ext == "MPC") + return new MPC::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "WV") + return new WavPack::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "SPX") + return new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "OPUS") + return new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "TTA") + return new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V") + return new MP4::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "WMA" || ext == "ASF") + return new ASF::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") + return new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "WAV") + return new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "APE") + return new APE::File(stream, readAudioProperties, audioPropertiesStyle); + // module, nst and wow are possible but uncommon extensions + if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") + return new Mod::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "S3M") + return new S3M::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "IT") + return new IT::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "XM") + return new XM::File(stream, readAudioProperties, audioPropertiesStyle); + + return 0; + } + + // Detect the file type based on the actual content of the stream. + + File *detectByContent(IOStream *stream, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { + File *file = 0; + + if(MPEG::File::isSupported(stream)) + file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + else if(Ogg::Vorbis::File::isSupported(stream)) + file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle); + 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); + else if(MPC::File::isSupported(stream)) + file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle); + else if(WavPack::File::isSupported(stream)) + file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle); + else if(Ogg::Speex::File::isSupported(stream)) + file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle); + else if(Ogg::Opus::File::isSupported(stream)) + file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle); + else if(TrueAudio::File::isSupported(stream)) + file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle); + else if(MP4::File::isSupported(stream)) + file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle); + else if(ASF::File::isSupported(stream)) + file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle); + else if(RIFF::AIFF::File::isSupported(stream)) + file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle); + else if(RIFF::WAV::File::isSupported(stream)) + file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle); + else if(APE::File::isSupported(stream)) + file = new APE::File(stream, readAudioProperties, audioPropertiesStyle); + + // isSupported() only does a quick check, so double check the file here. + + if(file) { + if(file->isValid()) + return file; + else + delete file; + } + + return 0; + } + + // Internal function that supports FileRef::create(). + // This looks redundant, but necessary in order not to change the previous + // behavior of FileRef::create(). + + File* createInternal(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { + File *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 0; + + 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 = new Ogg::FLAC::File(arg, readAudioProperties, audioPropertiesStyle); + File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); if(file->isValid()) return file; delete file; - return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle); + return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); } if(ext == "FLAC") - return new FLAC::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + return new FLAC::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); if(ext == "MPC") - return new MPC::File(arg, readAudioProperties, audioPropertiesStyle); + return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WV") - return new WavPack::File(arg, readAudioProperties, audioPropertiesStyle); + return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "SPX") - return new Ogg::Speex::File(arg, readAudioProperties, audioPropertiesStyle); + return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OPUS") - return new Ogg::Opus::File(arg, readAudioProperties, audioPropertiesStyle); + return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "TTA") - return new TrueAudio::File(arg, readAudioProperties, audioPropertiesStyle); + 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(arg, readAudioProperties, audioPropertiesStyle); + return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WMA" || ext == "ASF") - return new ASF::File(arg, readAudioProperties, audioPropertiesStyle); + return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") - return new RIFF::AIFF::File(arg, readAudioProperties, audioPropertiesStyle); + return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WAV") - return new RIFF::WAV::File(arg, readAudioProperties, audioPropertiesStyle); + return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "APE") - return new APE::File(arg, readAudioProperties, audioPropertiesStyle); + 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(arg, readAudioProperties, audioPropertiesStyle); + return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "S3M") - return new S3M::File(arg, readAudioProperties, audioPropertiesStyle); + return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "IT") - return new IT::File(arg, readAudioProperties, audioPropertiesStyle); + return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "XM") - return new XM::File(arg, readAudioProperties, audioPropertiesStyle); + return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); return 0; } @@ -186,15 +263,18 @@ namespace class FileRef::FileRefPrivate : public RefCounter { public: - FileRefPrivate(File *f) : + FileRefPrivate() : RefCounter(), - file(f) {} + file(0), + stream(0) {} ~FileRefPrivate() { delete file; + delete stream; } - File *file; + File *file; + IOStream *stream; }; //////////////////////////////////////////////////////////////////////////////// @@ -202,24 +282,27 @@ public: //////////////////////////////////////////////////////////////////////////////// FileRef::FileRef() : - d(new FileRefPrivate(0)) + d(new FileRefPrivate()) { } FileRef::FileRef(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : - d(new FileRefPrivate(createInternal(fileName, readAudioProperties, audioPropertiesStyle))) + d(new FileRefPrivate()) { + parse(fileName, readAudioProperties, audioPropertiesStyle); } FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : - d(new FileRefPrivate(createInternal(stream, readAudioProperties, audioPropertiesStyle))) + d(new FileRefPrivate()) { + parse(stream, readAudioProperties, audioPropertiesStyle); } FileRef::FileRef(File *file) : - d(new FileRefPrivate(file)) + d(new FileRefPrivate()) { + d->file = file; } FileRef::FileRef(const FileRef &ref) : @@ -341,3 +424,51 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, { return createInternal(fileName, readAudioProperties, audioPropertiesStyle); } + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void FileRef::parse(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) +{ + // Try user-defined resolvers. + + d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); + if(d->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) + return; + + // At last, try to resolve file types based on the actual content. + + d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle); + if(d->file) + return; + + // Stream have to be closed here if failed to resolve file types. + + delete d->stream; + d->stream = 0; +} + +void FileRef::parse(IOStream *stream, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) +{ + // User-defined resolvers won't work with a stream. + + // Try to resolve file types based on the file extension. + + d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle); + if(d->file) + return; + + // At last, try to resolve file types based on the actual content of the file. + + d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle); +} diff --git a/3rdparty/taglib/fileref.h b/3rdparty/taglib/fileref.h index a12b1a9b1..c36f54cbd 100644 --- a/3rdparty/taglib/fileref.h +++ b/3rdparty/taglib/fileref.h @@ -274,8 +274,10 @@ namespace TagLib { 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); + class FileRefPrivate; FileRefPrivate *d; }; diff --git a/3rdparty/taglib/flac/flacfile.cpp b/3rdparty/taglib/flac/flacfile.cpp index b31cc65e0..7f4371943 100644 --- a/3rdparty/taglib/flac/flacfile.cpp +++ b/3rdparty/taglib/flac/flacfile.cpp @@ -95,6 +95,18 @@ public: bool scanned; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool FLAC::File::isSupported(IOStream *stream) +{ + // A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); + return (buffer.find("fLaC") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -168,8 +180,8 @@ bool FLAC::File::save() } // Create new vorbis comments - - Tag::duplicate(&d->tag, xiphComment(true), false); + if(!hasXiphComment()) + Tag::duplicate(&d->tag, xiphComment(true), false); d->xiphCommentData = xiphComment()->render(false); @@ -198,7 +210,6 @@ bool FLAC::File::save() } // Compute the amount of padding, and append that to data. - // TODO: Should be calculated in offset_t in taglib2. long originalLength = d->streamStart - d->flacStart; long paddingLength = originalLength - data.size() - 4; @@ -298,11 +309,7 @@ bool FLAC::File::save() ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) { - if(!create || d->tag[FlacID3v2Index]) - return static_cast(d->tag[FlacID3v2Index]); - - d->tag.set(FlacID3v2Index, new ID3v2::Tag); - return static_cast(d->tag[FlacID3v2Index]); + return d->tag.access(FlacID3v2Index, create); } ID3v1::Tag *FLAC::File::ID3v1Tag(bool create) @@ -507,7 +514,9 @@ void FLAC::File::scan() return; } - if(blockLength == 0 && blockType != MetadataBlock::Padding) { + if(blockLength == 0 + && blockType != MetadataBlock::Padding && blockType != MetadataBlock::SeekTable) + { debug("FLAC::File::scan() -- Zero-sized metadata block found"); setValid(false); return; diff --git a/3rdparty/taglib/flac/flacfile.h b/3rdparty/taglib/flac/flacfile.h index 65d856792..645090e0e 100644 --- a/3rdparty/taglib/flac/flacfile.h +++ b/3rdparty/taglib/flac/flacfile.h @@ -318,6 +318,15 @@ namespace TagLib { */ bool hasID3v2Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as a FLAC + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/flac/flacpicture.cpp b/3rdparty/taglib/flac/flacpicture.cpp index 72c972477..ec07ad140 100644 --- a/3rdparty/taglib/flac/flacpicture.cpp +++ b/3rdparty/taglib/flac/flacpicture.cpp @@ -50,14 +50,14 @@ public: ByteVector data; }; -FLAC::Picture::Picture() +FLAC::Picture::Picture() : + d(new PicturePrivate()) { - d = new PicturePrivate; } -FLAC::Picture::Picture(const ByteVector &data) +FLAC::Picture::Picture(const ByteVector &data) : + d(new PicturePrivate()) { - d = new PicturePrivate; parse(data); } diff --git a/3rdparty/taglib/flac/flacunknownmetadatablock.cpp b/3rdparty/taglib/flac/flacunknownmetadatablock.cpp index dcd5d6515..f9cf6e658 100644 --- a/3rdparty/taglib/flac/flacunknownmetadatablock.cpp +++ b/3rdparty/taglib/flac/flacunknownmetadatablock.cpp @@ -39,11 +39,10 @@ public: ByteVector data; }; -FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) +FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) : + d(new UnknownMetadataBlockPrivate()) { - d = new UnknownMetadataBlockPrivate; d->code = code; - //debug(String(data.toHex())); d->data = data; } diff --git a/3rdparty/taglib/it/itproperties.cpp b/3rdparty/taglib/it/itproperties.cpp index 8f686dc7b..c317b660e 100644 --- a/3rdparty/taglib/it/itproperties.cpp +++ b/3rdparty/taglib/it/itproperties.cpp @@ -70,7 +70,7 @@ public: IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), - d(new PropertiesPrivate) + d(new PropertiesPrivate()) { } diff --git a/3rdparty/taglib/mod/modproperties.cpp b/3rdparty/taglib/mod/modproperties.cpp index ed3df94d4..c6bf39475 100644 --- a/3rdparty/taglib/mod/modproperties.cpp +++ b/3rdparty/taglib/mod/modproperties.cpp @@ -46,7 +46,7 @@ public: Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), - d(new PropertiesPrivate) + d(new PropertiesPrivate()) { } diff --git a/3rdparty/taglib/mod/modtag.cpp b/3rdparty/taglib/mod/modtag.cpp index 616d8c1b1..0e8d03719 100644 --- a/3rdparty/taglib/mod/modtag.cpp +++ b/3rdparty/taglib/mod/modtag.cpp @@ -43,9 +43,10 @@ public: String trackerName; }; -Mod::Tag::Tag() : TagLib::Tag() +Mod::Tag::Tag() : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; } Mod::Tag::~Tag() diff --git a/3rdparty/taglib/mp4/mp4atom.cpp b/3rdparty/taglib/mp4/mp4atom.cpp index 6ea0cb62c..20709212e 100644 --- a/3rdparty/taglib/mp4/mp4atom.cpp +++ b/3rdparty/taglib/mp4/mp4atom.cpp @@ -54,24 +54,25 @@ MP4::Atom::Atom(File *file) length = header.toUInt(); - if(length == 1) { + if(length == 0) { + // The last atom which extends to the end of the file. + length = file->length() - offset; + } + else if(length == 1) { + // The atom has a 64-bit length. const long long longLength = file->readBlock(8).toLongLong(); - if(sizeof(long) == sizeof(long long)) { + 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 { - if(longLength <= LONG_MAX) { - // The atom has a 64-bit length, but it's actually a 31-bit value - length = static_cast(longLength); - } - else { - debug("MP4: 64-bit atoms are not supported"); - length = 0; - file->seek(0, File::End); - return; - } + debug("MP4: 64-bit atoms are not supported"); + length = 0; + file->seek(0, File::End); + return; } } + if(length < 8) { debug("MP4: Invalid atom size"); length = 0; diff --git a/3rdparty/taglib/mp4/mp4file.cpp b/3rdparty/taglib/mp4/mp4file.cpp index 3733fb40d..5ad8396de 100644 --- a/3rdparty/taglib/mp4/mp4file.cpp +++ b/3rdparty/taglib/mp4/mp4file.cpp @@ -26,6 +26,8 @@ #include #include #include +#include + #include "mp4atom.h" #include "mp4tag.h" #include "mp4file.h" @@ -69,6 +71,22 @@ public: MP4::Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool MP4::File::isSupported(IOStream *stream) +{ + // An MP4 file has to have an "ftyp" box first. + + const ByteVector id = Utils::readHeader(stream, 8, false); + return id.containsAt("ftyp", 4); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) : TagLib::File(file), d(new FilePrivate()) diff --git a/3rdparty/taglib/mp4/mp4file.h b/3rdparty/taglib/mp4/mp4file.h index 3840bd022..8a46d17df 100644 --- a/3rdparty/taglib/mp4/mp4file.h +++ b/3rdparty/taglib/mp4/mp4file.h @@ -120,6 +120,15 @@ namespace TagLib { */ bool hasMP4Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as an ASF + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: void read(bool readProperties); diff --git a/3rdparty/taglib/mp4/mp4tag.cpp b/3rdparty/taglib/mp4/mp4tag.cpp index a8e2e7d3e..a3636a9d6 100644 --- a/3rdparty/taglib/mp4/mp4tag.cpp +++ b/3rdparty/taglib/mp4/mp4tag.cpp @@ -71,14 +71,15 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) : parseIntPair(atom); } else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" || - atom->name == "hdvd") { + atom->name == "hdvd" || atom->name == "shwm") { parseBool(atom); } - else if(atom->name == "tmpo") { + else if(atom->name == "tmpo" || atom->name == "rate" || atom->name == "\251mvi" || atom->name == "\251mvc") { parseInt(atom); } else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" || - atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") { + atom->name == "sfID" || atom->name == "atID" || atom->name == "geID" || + atom->name == "cmID") { parseUInt(atom); } else if(atom->name == "plID") { @@ -93,6 +94,9 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) : else if(atom->name == "covr") { parseCovr(atom); } + else if(atom->name == "purl" || atom->name == "egid") { + parseText(atom, -1); + } else { parseText(atom); } @@ -472,14 +476,16 @@ MP4::Tag::save() else if(name == "disk") { data.append(renderIntPairNoTrailing(name.data(String::Latin1), it->second)); } - else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") { + else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd" || + name == "shwm") { data.append(renderBool(name.data(String::Latin1), it->second)); } - else if(name == "tmpo") { + else if(name == "tmpo" || name == "rate" || name == "\251mvi" || name == "\251mvc") { data.append(renderInt(name.data(String::Latin1), it->second)); } else if(name == "tvsn" || name == "tves" || name == "cnID" || - name == "sfID" || name == "atID" || name == "geID") { + name == "sfID" || name == "atID" || name == "geID" || + name == "cmID") { data.append(renderUInt(name.data(String::Latin1), it->second)); } else if(name == "plID") { @@ -491,6 +497,9 @@ MP4::Tag::save() else if(name == "covr") { data.append(renderCovr(name.data(String::Latin1), it->second)); } + else if(name == "purl" || name == "egid") { + data.append(renderText(name.data(String::Latin1), it->second, TypeImplicit)); + } else if(name.size() == 4){ data.append(renderText(name.data(String::Latin1), it->second)); } @@ -844,6 +853,11 @@ namespace { "sonm", "TITLESORT" }, { "soco", "COMPOSERSORT" }, { "sosn", "SHOWSORT" }, + { "shwm", "SHOWWORKMOVEMENT" }, + { "\251wrk", "WORK" }, + { "\251mvn", "MOVEMENTNAME" }, + { "\251mvi", "MOVEMENTNUMBER" }, + { "\251mvc", "MOVEMENTCOUNT" }, { "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" }, { "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, { "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, @@ -897,10 +911,10 @@ PropertyMap MP4::Tag::properties() const } props[key] = value; } - else if(key == "BPM") { + else if(key == "BPM" || key == "MOVEMENTNUMBER" || key == "MOVEMENTCOUNT") { props[key] = String::number(it->second.toInt()); } - else if(key == "COMPILATION") { + else if(key == "COMPILATION" || key == "SHOWWORKMOVEMENT") { props[key] = String::number(it->second.toBool()); } else { @@ -942,21 +956,21 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props) if(reverseKeyMap.contains(it->first)) { String name = reverseKeyMap[it->first]; if((it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") && !it->second.isEmpty()) { - int first = 0, second = 0; StringList parts = StringList::split(it->second.front(), "/"); if(!parts.isEmpty()) { - first = parts[0].toInt(); + int first = parts[0].toInt(); + int second = 0; if(parts.size() > 1) { second = parts[1].toInt(); } d->items[name] = MP4::Item(first, second); } } - else if(it->first == "BPM" && !it->second.isEmpty()) { + else if((it->first == "BPM" || it->first == "MOVEMENTNUMBER" || it->first == "MOVEMENTCOUNT") && !it->second.isEmpty()) { int value = it->second.front().toInt(); d->items[name] = MP4::Item(value); } - else if(it->first == "COMPILATION" && !it->second.isEmpty()) { + else if((it->first == "COMPILATION" || it->first == "SHOWWORKMOVEMENT") && !it->second.isEmpty()) { bool value = (it->second.front().toInt() != 0); d->items[name] = MP4::Item(value); } diff --git a/3rdparty/taglib/mpc/mpcfile.cpp b/3rdparty/taglib/mpc/mpcfile.cpp index daf24c8fb..0ffaf8933 100644 --- a/3rdparty/taglib/mpc/mpcfile.cpp +++ b/3rdparty/taglib/mpc/mpcfile.cpp @@ -75,6 +75,19 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool MPC::File::isSupported(IOStream *stream) +{ + // A newer MPC file has to start with "MPCK" or "MP+", but older files don't + // have keys to do a quick check. + + const ByteVector id = Utils::readHeader(stream, 4, false); + return (id == "MPCK" || id.startsWith("MP+")); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/mpc/mpcfile.h b/3rdparty/taglib/mpc/mpcfile.h index 541724dc2..89a866e3b 100644 --- a/3rdparty/taglib/mpc/mpcfile.h +++ b/3rdparty/taglib/mpc/mpcfile.h @@ -214,6 +214,15 @@ namespace TagLib { */ bool hasAPETag() const; + /*! + * Returns whether or not the given \a stream can be opened as an MPC + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp index 849ee9ff2..8e2630cef 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp @@ -48,14 +48,16 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC") +AttachedPictureFrame::AttachedPictureFrame() : + Frame("APIC"), + d(new AttachedPictureFramePrivate()) { - d = new AttachedPictureFramePrivate; } -AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data) +AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : + Frame(data), + d(new AttachedPictureFramePrivate()) { - d = new AttachedPictureFramePrivate; setData(data); } @@ -169,9 +171,10 @@ ByteVector AttachedPictureFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h) +AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new AttachedPictureFramePrivate()) { - d = new AttachedPictureFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp index 44cdf5e77..69fe1df0a 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp @@ -37,7 +37,11 @@ class ChapterFrame::ChapterFramePrivate { public: ChapterFramePrivate() : - tagHeader(0) + tagHeader(0), + startTime(0), + endTime(0), + startOffset(0), + endOffset(0) { embeddedFrameList.setAutoDelete(true); } @@ -57,9 +61,9 @@ public: //////////////////////////////////////////////////////////////////////////////// ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : - ID3v2::Frame(data) + ID3v2::Frame(data), + d(new ChapterFramePrivate()) { - d = new ChapterFramePrivate; d->tagHeader = tagHeader; setData(data); } @@ -68,10 +72,9 @@ ChapterFrame::ChapterFrame(const ByteVector &elementID, unsigned int startTime, unsigned int endTime, unsigned int startOffset, unsigned int endOffset, const FrameList &embeddedFrames) : - ID3v2::Frame("CHAP") + ID3v2::Frame("CHAP"), + d(new ChapterFramePrivate()) { - d = new ChapterFramePrivate; - // setElementID has a workaround for a previously silly API where you had to // specifically include the null byte. @@ -198,7 +201,7 @@ String ChapterFrame::toString() const s += ", start offset: " + String::number(d->startOffset); if(d->endOffset != 0xFFFFFFFF) - s += ", start offset: " + String::number(d->endOffset); + s += ", end offset: " + String::number(d->endOffset); if(!d->embeddedFrameList.isEmpty()) { StringList frameIDs; @@ -298,9 +301,9 @@ ByteVector ChapterFrame::renderFields() const } ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : - Frame(h) + Frame(h), + d(new ChapterFramePrivate()) { - d = new ChapterFramePrivate; d->tagHeader = tagHeader; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp index b56183226..815e5e1a1 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp @@ -48,15 +48,17 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM") +CommentsFrame::CommentsFrame(String::Type encoding) : + Frame("COMM"), + d(new CommentsFramePrivate()) { - d = new CommentsFramePrivate; d->textEncoding = encoding; } -CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data) +CommentsFrame::CommentsFrame(const ByteVector &data) : + Frame(data), + d(new CommentsFramePrivate()) { - d = new CommentsFramePrivate; setData(data); } @@ -188,8 +190,9 @@ ByteVector CommentsFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h) +CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new CommentsFramePrivate()) { - d = new CommentsFramePrivate(); parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp index 7af797f08..930318123 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp @@ -46,15 +46,15 @@ public: //////////////////////////////////////////////////////////////////////////////// EventTimingCodesFrame::EventTimingCodesFrame() : - Frame("ETCO") + Frame("ETCO"), + d(new EventTimingCodesFramePrivate()) { - d = new EventTimingCodesFramePrivate; } EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) : - Frame(data) + Frame(data), + d(new EventTimingCodesFramePrivate()) { - d = new EventTimingCodesFramePrivate; setData(data); } @@ -136,9 +136,9 @@ ByteVector EventTimingCodesFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) - : Frame(h) +EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new EventTimingCodesFramePrivate()) { - d = new EventTimingCodesFramePrivate(); parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp index 1c773837f..c9b2f6dc4 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp @@ -50,14 +50,16 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB") +GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : + Frame("GEOB"), + d(new GeneralEncapsulatedObjectFramePrivate()) { - d = new GeneralEncapsulatedObjectFramePrivate; } -GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data) +GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : + Frame(data), + d(new GeneralEncapsulatedObjectFramePrivate()) { - d = new GeneralEncapsulatedObjectFramePrivate; setData(data); } @@ -177,8 +179,9 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h) +GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new GeneralEncapsulatedObjectFramePrivate()) { - d = new GeneralEncapsulatedObjectFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp index 83a598245..0b180dbf6 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp @@ -45,15 +45,17 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE") +OwnershipFrame::OwnershipFrame(String::Type encoding) : + Frame("OWNE"), + d(new OwnershipFramePrivate()) { - d = new OwnershipFramePrivate; d->textEncoding = encoding; } -OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data) +OwnershipFrame::OwnershipFrame(const ByteVector &data) : + Frame(data), + d(new OwnershipFramePrivate()) { - d = new OwnershipFramePrivate; setData(data); } @@ -161,8 +163,9 @@ ByteVector OwnershipFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h) +OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new OwnershipFramePrivate()) { - d = new OwnershipFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp index 5115a7dd1..7285b9689 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp @@ -38,9 +38,10 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -PodcastFrame::PodcastFrame() : Frame("PCST") +PodcastFrame::PodcastFrame() : + Frame("PCST"), + d(new PodcastFramePrivate()) { - d = new PodcastFramePrivate; d->fieldData = ByteVector(4, '\0'); } @@ -72,8 +73,9 @@ ByteVector PodcastFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h) +PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new PodcastFramePrivate()) { - d = new PodcastFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp index dac8589f3..9106fabd5 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp @@ -43,14 +43,16 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -PopularimeterFrame::PopularimeterFrame() : Frame("POPM") +PopularimeterFrame::PopularimeterFrame() : + Frame("POPM"), + d(new PopularimeterFramePrivate()) { - d = new PopularimeterFramePrivate; } -PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data) +PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : + Frame(data), + d(new PopularimeterFramePrivate()) { - d = new PopularimeterFramePrivate; setData(data); } @@ -130,8 +132,9 @@ ByteVector PopularimeterFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h) +PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new PopularimeterFramePrivate()) { - d = new PopularimeterFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp index 24ee0f350..be80c4df8 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp @@ -45,14 +45,16 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -PrivateFrame::PrivateFrame() : Frame("PRIV") +PrivateFrame::PrivateFrame() : + Frame("PRIV"), + d(new PrivateFramePrivate()) { - d = new PrivateFramePrivate; } -PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data) +PrivateFrame::PrivateFrame(const ByteVector &data) : + Frame(data), + d(new PrivateFramePrivate()) { - d = new PrivateFramePrivate; setData(data); } @@ -121,8 +123,9 @@ ByteVector PrivateFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h) +PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new PrivateFramePrivate()) { - d = new PrivateFramePrivate(); parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp index a907f6b97..3398ada82 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp @@ -51,14 +51,16 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2") +RelativeVolumeFrame::RelativeVolumeFrame() : + Frame("RVA2"), + d(new RelativeVolumeFramePrivate()) { - d = new RelativeVolumeFramePrivate; } -RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data) +RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : + Frame(data), + d(new RelativeVolumeFramePrivate()) { - d = new RelativeVolumeFramePrivate; setData(data); } @@ -223,8 +225,9 @@ ByteVector RelativeVolumeFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h) +RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new RelativeVolumeFramePrivate()) { - d = new RelativeVolumeFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp index c3b50c7ec..6a62bb495 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp @@ -52,16 +52,16 @@ public: //////////////////////////////////////////////////////////////////////////////// SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) : - Frame("SYLT") + Frame("SYLT"), + d(new SynchronizedLyricsFramePrivate()) { - d = new SynchronizedLyricsFramePrivate; d->textEncoding = encoding; } SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) : - Frame(data) + Frame(data), + d(new SynchronizedLyricsFramePrivate()) { - d = new SynchronizedLyricsFramePrivate; setData(data); } @@ -189,7 +189,7 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) } } String text = readStringField(data, enc, &pos); - if(text.isEmpty() || pos + 4 > end) + if(pos + 4 > end) return; unsigned int time = data.toUInt(pos, true); @@ -234,9 +234,9 @@ ByteVector SynchronizedLyricsFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) - : Frame(h) +SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new SynchronizedLyricsFramePrivate()) { - d = new SynchronizedLyricsFramePrivate(); parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp index 507203590..ddd3b88c6 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp @@ -36,7 +36,9 @@ class TableOfContentsFrame::TableOfContentsFramePrivate { public: TableOfContentsFramePrivate() : - tagHeader(0) + tagHeader(0), + isTopLevel(false), + isOrdered(false) { embeddedFrameList.setAutoDelete(true); } @@ -80,9 +82,9 @@ namespace { //////////////////////////////////////////////////////////////////////////////// TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : - ID3v2::Frame(data) + ID3v2::Frame(data), + d(new TableOfContentsFramePrivate()) { - d = new TableOfContentsFramePrivate; d->tagHeader = tagHeader; setData(data); } @@ -90,9 +92,9 @@ TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID, const ByteVectorList &children, const FrameList &embeddedFrames) : - ID3v2::Frame("CTOC") + ID3v2::Frame("CTOC"), + d(new TableOfContentsFramePrivate()) { - d = new TableOfContentsFramePrivate; d->elementID = elementID; strip(d->elementID); d->childElements = children; @@ -272,9 +274,9 @@ void TableOfContentsFrame::parseFields(const ByteVector &data) int pos = 0; unsigned int embPos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); - d->isTopLevel = (data.at(pos) & 2) > 0; - d->isOrdered = (data.at(pos++) & 1) > 0; - unsigned int entryCount = data.at(pos++); + 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); d->childElements.append(childElementID); @@ -330,9 +332,9 @@ ByteVector TableOfContentsFrame::renderFields() const TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : - Frame(h) + Frame(h), + d(new TableOfContentsFramePrivate()) { - d = new TableOfContentsFramePrivate; d->tagHeader = tagHeader; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h index 31196b2e3..2e5401e8a 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h +++ b/3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h @@ -29,6 +29,8 @@ #include "id3v2tag.h" #include "id3v2frame.h" +#include "tbytevectorlist.h" + namespace TagLib { namespace ID3v2 { diff --git a/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp index d9d3b29bc..db9a177e5 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -45,16 +45,16 @@ public: //////////////////////////////////////////////////////////////////////////////// TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) : - Frame(type) + Frame(type), + d(new TextIdentificationFramePrivate()) { - d = new TextIdentificationFramePrivate; d->textEncoding = encoding; } TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : - Frame(data) + Frame(data), + d(new TextIdentificationFramePrivate()) { - d = new TextIdentificationFramePrivate; setData(data); } @@ -252,9 +252,10 @@ ByteVector TextIdentificationFrame::renderFields() const // TextIdentificationFrame private members //////////////////////////////////////////////////////////////////////////////// -TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h) +TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new TextIdentificationFramePrivate()) { - d = new TextIdentificationFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp index a986e4db4..fcb855b2e 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp @@ -45,16 +45,16 @@ public: //////////////////////////////////////////////////////////////////////////////// UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) : - ID3v2::Frame(data) + ID3v2::Frame(data), + d(new UniqueFileIdentifierFramePrivate()) { - d = new UniqueFileIdentifierFramePrivate; setData(data); } UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) : - ID3v2::Frame("UFID") + ID3v2::Frame("UFID"), + d(new UniqueFileIdentifierFramePrivate()) { - d = new UniqueFileIdentifierFramePrivate; d->owner = owner; d->identifier = id; } @@ -141,8 +141,8 @@ ByteVector UniqueFileIdentifierFrame::renderFields() const } UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) : - Frame(h) + Frame(h), + d(new UniqueFileIdentifierFramePrivate()) { - d = new UniqueFileIdentifierFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp index 9d059193b..edb30084a 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp @@ -38,9 +38,10 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data) +UnknownFrame::UnknownFrame(const ByteVector &data) : + Frame(data), + d(new UnknownFramePrivate()) { - d = new UnknownFramePrivate; setData(data); } @@ -77,8 +78,9 @@ ByteVector UnknownFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h) +UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new UnknownFramePrivate()) { - d = new UnknownFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp index 3d610c9a7..eafae171c 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp @@ -50,16 +50,16 @@ public: //////////////////////////////////////////////////////////////////////////////// UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) : - Frame("USLT") + Frame("USLT"), + d(new UnsynchronizedLyricsFramePrivate()) { - d = new UnsynchronizedLyricsFramePrivate; d->textEncoding = encoding; } UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) : - Frame(data) + Frame(data), + d(new UnsynchronizedLyricsFramePrivate()) { - d = new UnsynchronizedLyricsFramePrivate; setData(data); } @@ -118,7 +118,7 @@ PropertyMap UnsynchronizedLyricsFrame::asProperties() const { PropertyMap map; String key = description().upper(); - if(key.isEmpty() || key.upper() == "LYRICS") + if(key.isEmpty() || key == "LYRICS") map.insert("LYRICS", text()); else map.insert("LYRICS:" + key, text()); @@ -190,9 +190,9 @@ ByteVector UnsynchronizedLyricsFrame::renderFields() const // private members //////////////////////////////////////////////////////////////////////////////// -UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) - : Frame(h) +UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new UnsynchronizedLyricsFramePrivate()) { - d = new UnsynchronizedLyricsFramePrivate(); parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp index 42d807122..543b5184d 100644 --- a/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp +++ b/3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp @@ -49,10 +49,14 @@ public: String description; }; +//////////////////////////////////////////////////////////////////////////////// +// UrlLinkFrame public members +//////////////////////////////////////////////////////////////////////////////// + UrlLinkFrame::UrlLinkFrame(const ByteVector &data) : - Frame(data) + Frame(data), + d(new UrlLinkFramePrivate()) { - d = new UrlLinkFramePrivate; setData(data); } @@ -93,6 +97,10 @@ PropertyMap UrlLinkFrame::asProperties() const return map; } +//////////////////////////////////////////////////////////////////////////////// +// UrlLinkFrame protected members +//////////////////////////////////////////////////////////////////////////////// + void UrlLinkFrame::parseFields(const ByteVector &data) { d->url = String(data); @@ -103,24 +111,28 @@ ByteVector UrlLinkFrame::renderFields() const return d->url.data(String::Latin1); } -UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h) +UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : + Frame(h), + d(new UrlLinkFramePrivate()) { - d = new UrlLinkFramePrivate; parseFields(fieldData(data)); } +//////////////////////////////////////////////////////////////////////////////// +// UserUrlLinkFrame public members +//////////////////////////////////////////////////////////////////////////////// UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) : - UrlLinkFrame("WXXX") + UrlLinkFrame("WXXX"), + d(new UserUrlLinkFramePrivate()) { - d = new UserUrlLinkFramePrivate; d->textEncoding = encoding; } UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) : - UrlLinkFrame(data) + UrlLinkFrame(data), + d(new UserUrlLinkFramePrivate()) { - d = new UserUrlLinkFramePrivate; setData(data); } @@ -158,7 +170,7 @@ PropertyMap UserUrlLinkFrame::asProperties() const { PropertyMap map; String key = description().upper(); - if(key.isEmpty() || key.upper() == "URL") + if(key.isEmpty() || key == "URL") map.insert("URL", url()); else map.insert("URL:" + key, url()); @@ -176,6 +188,10 @@ UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &descript return 0; } +//////////////////////////////////////////////////////////////////////////////// +// UserUrlLinkFrame protected members +//////////////////////////////////////////////////////////////////////////////// + void UserUrlLinkFrame::parseFields(const ByteVector &data) { if(data.size() < 2) { @@ -222,8 +238,9 @@ ByteVector UserUrlLinkFrame::renderFields() const return v; } -UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h) +UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : + UrlLinkFrame(data, h), + d(new UserUrlLinkFramePrivate()) { - d = new UserUrlLinkFramePrivate; parseFields(fieldData(data)); } diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp index 667e3e94a..86eeee280 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp @@ -41,9 +41,9 @@ public: // public methods //////////////////////////////////////////////////////////////////////////////// -ExtendedHeader::ExtendedHeader() +ExtendedHeader::ExtendedHeader() : + d(new ExtendedHeaderPrivate()) { - d = new ExtendedHeaderPrivate(); } ExtendedHeader::~ExtendedHeader() diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp index 1f896fa6e..4f88dec1f 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp @@ -111,8 +111,8 @@ Frame *Frame::createTextualFrame(const String &key, const StringList &values) // // check if the key is contained in the key<=>frameID mapping ByteVector frameID = keyToFrameID(key); if(!frameID.isEmpty()) { - // Apple proprietary WFED (Podcast URL) is in fact a text frame. - if(frameID[0] == 'T' || frameID == "WFED"){ // text frame + // Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number) are in fact text frames. + if(frameID[0] == 'T' || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN"){ // text frame TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8); frame->setText(values); return frame; @@ -198,15 +198,15 @@ ByteVector Frame::render() const // protected members //////////////////////////////////////////////////////////////////////////////// -Frame::Frame(const ByteVector &data) +Frame::Frame(const ByteVector &data) : + d(new FramePrivate()) { - d = new FramePrivate; d->header = new Header(data); } -Frame::Frame(Header *h) +Frame::Frame(Header *h) : + d(new FramePrivate()) { - d = new FramePrivate; d->header = h; } @@ -392,6 +392,8 @@ namespace { "TDES", "PODCASTDESC" }, { "TGID", "PODCASTID" }, { "WFED", "PODCASTURL" }, + { "MVNM", "MOVEMENTNAME" }, + { "MVIN", "MOVEMENTNUMBER" }, }; const size_t frameTranslationSize = sizeof(frameTranslation) / sizeof(frameTranslation[0]); @@ -474,8 +476,8 @@ PropertyMap Frame::asProperties() const // workaround until this function is virtual if(id == "TXXX") return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties(); - // Apple proprietary WFED (Podcast URL) is in fact a text frame. - else if(id[0] == 'T' || id == "WFED") + // Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number) are in fact text frames. + else if(id[0] == 'T' || id == "WFED" || id == "MVNM" || id == "MVIN") return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties(); else if(id == "WXXX") return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties(); @@ -571,15 +573,15 @@ unsigned int Frame::Header::size(unsigned int version) // public members (Frame::Header) //////////////////////////////////////////////////////////////////////////////// -Frame::Header::Header(const ByteVector &data, bool synchSafeInts) +Frame::Header::Header(const ByteVector &data, bool synchSafeInts) : + d(new HeaderPrivate()) { - d = new HeaderPrivate; setData(data, synchSafeInts); } -Frame::Header::Header(const ByteVector &data, unsigned int version) +Frame::Header::Header(const ByteVector &data, unsigned int version) : + d(new HeaderPrivate()) { - d = new HeaderPrivate; setData(data, version); } diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp index 0fbb87d02..9347ab869 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -198,8 +198,8 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) // Text Identification (frames 4.2) - // Apple proprietary WFED (Podcast URL) is in fact a text frame. - if(frameID.startsWith("T") || frameID == "WFED") { + // Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number) are in fact text frames. + if(frameID.startsWith("T") || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN") { TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) @@ -334,10 +334,11 @@ void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const tag->frameList("TDAT").size() == 1) { TextIdentificationFrame *tdrc = - static_cast(tag->frameList("TDRC").front()); + dynamic_cast(tag->frameList("TDRC").front()); UnknownFrame *tdat = static_cast(tag->frameList("TDAT").front()); - if(tdrc->fieldList().size() == 1 && + if(tdrc && + tdrc->fieldList().size() == 1 && tdrc->fieldList().front().size() == 4 && tdat->data().size() >= 5) { @@ -456,6 +457,8 @@ namespace { "TDS", "TDES" }, { "TID", "TGID" }, { "WFD", "WFED" }, + { "MVN", "MVNM" }, + { "MVI", "MVIN" }, }; const size_t frameConversion2Size = sizeof(frameConversion2) / sizeof(frameConversion2[0]); diff --git a/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp b/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp index 4c00ab6fb..525e88b63 100644 --- a/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp @@ -60,6 +60,7 @@ class ID3v2::Tag::TagPrivate { public: TagPrivate() : + factory(0), file(0), tagOffset(0), extendedHeader(0), @@ -286,7 +287,7 @@ void ID3v2::Tag::setGenre(const String &s) void ID3v2::Tag::setYear(unsigned int i) { - if(i <= 0) { + if(i == 0) { removeFrames("TDRC"); return; } @@ -295,7 +296,7 @@ void ID3v2::Tag::setYear(unsigned int i) void ID3v2::Tag::setTrack(unsigned int i) { - if(i <= 0) { + if(i == 0) { removeFrames("TRCK"); return; } @@ -618,7 +619,6 @@ ByteVector ID3v2::Tag::render(int version) const } // Compute the amount of padding, and append that to tagData. - // TODO: Should be calculated in long long in taglib2. long originalSize = d->header.tagSize(); long paddingSize = originalSize - (tagData.size() - Header::size()); @@ -723,7 +723,7 @@ void ID3v2::Tag::parse(const ByteVector &origData) if(d->header.extendedHeader()) { if(!d->extendedHeader) - d->extendedHeader = new ExtendedHeader; + d->extendedHeader = new ExtendedHeader(); d->extendedHeader->setData(data); if(d->extendedHeader->size() <= data.size()) { frameDataPosition += d->extendedHeader->size(); diff --git a/3rdparty/taglib/mpeg/mpegfile.cpp b/3rdparty/taglib/mpeg/mpegfile.cpp index af7253fa5..517aea569 100644 --- a/3rdparty/taglib/mpeg/mpegfile.cpp +++ b/3rdparty/taglib/mpeg/mpegfile.cpp @@ -76,6 +76,58 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +namespace +{ + // Dummy file class to make a stream work with MPEG::Header. + + class AdapterFile : public TagLib::File + { + public: + AdapterFile(IOStream *stream) : File(stream) {} + + Tag *tag() const { return 0; } + AudioProperties *audioProperties() const { return 0; } + bool save() { return false; } + }; +} + +bool MPEG::File::isSupported(IOStream *stream) +{ + if(!stream || !stream->isOpen()) + return false; + + // An MPEG file has MPEG frame headers. An ID3v2 tag may precede. + + // MPEG frame headers are really confusing with irrelevant binary data. + // So we check if a frame header is really valid. + + long headerOffset; + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true, &headerOffset); + + if(buffer.isEmpty()) + return false; + + const long originalPosition = stream->tell(); + AdapterFile file(stream); + + for(unsigned int i = 0; i < buffer.size() - 1; ++i) { + if(isFrameSync(buffer, i)) { + const Header header(&file, headerOffset + i, true); + if(header.isValid()) { + stream->seek(originalPosition); + return true; + } + } + } + + stream->seek(originalPosition); + return false; +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -346,55 +398,50 @@ void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) long MPEG::File::nextFrameOffset(long position) { - bool foundLastSyncPattern = false; - - ByteVector buffer; + ByteVector frameSyncBytes(2, '\0'); while(true) { seek(position); - buffer = readBlock(bufferSize()); - - if(buffer.size() <= 0) + const ByteVector buffer = readBlock(bufferSize()); + if(buffer.isEmpty()) return -1; - if(foundLastSyncPattern && secondSynchByte(buffer[0])) - return position - 1; - - for(unsigned int i = 0; i < buffer.size() - 1; i++) { - if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1])) - return position + i; + for(unsigned int i = 0; i < buffer.size(); ++i) { + frameSyncBytes[0] = frameSyncBytes[1]; + frameSyncBytes[1] = buffer[i]; + if(isFrameSync(frameSyncBytes)) { + const Header header(this, position + i - 1, true); + if(header.isValid()) + return position + i - 1; + } } - foundLastSyncPattern = firstSyncByte(buffer[buffer.size() - 1]); - position += buffer.size(); + position += bufferSize(); } } long MPEG::File::previousFrameOffset(long position) { - bool foundFirstSyncPattern = false; - ByteVector buffer; + ByteVector frameSyncBytes(2, '\0'); - while (position > 0) { - long size = std::min(position, bufferSize()); - position -= size; + while(position > 0) { + const long bufferLength = std::min(position, bufferSize()); + position -= bufferLength; seek(position); - buffer = readBlock(size); + const ByteVector buffer = readBlock(bufferLength); - if(buffer.size() <= 0) - break; - - if(foundFirstSyncPattern && firstSyncByte(buffer[buffer.size() - 1])) - return position + buffer.size() - 1; - - for(int i = buffer.size() - 2; i >= 0; i--) { - if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1])) - return position + i; + for(int i = buffer.size() - 1; i >= 0; --i) { + frameSyncBytes[1] = frameSyncBytes[0]; + frameSyncBytes[0] = buffer[i]; + if(isFrameSync(frameSyncBytes)) { + const Header header(this, position + i, true); + if(header.isValid()) + return position + i + header.frameLength(); + } } - - foundFirstSyncPattern = secondSynchByte(buffer[0]); } + return -1; } @@ -488,28 +535,41 @@ long MPEG::File::findID3v2() const ByteVector headerID = ID3v2::Header::fileIdentifier(); seek(0); - - const ByteVector data = readBlock(headerID.size()); - if(data.size() < headerID.size()) - return -1; - - if(data == headerID) + if(readBlock(headerID.size()) == headerID) return 0; - if(firstSyncByte(data[0]) && secondSynchByte(data[1])) + const Header firstHeader(this, 0, true); + if(firstHeader.isValid()) return -1; - // Look for the entire file, if neither an MEPG frame or ID3v2 tag was found - // at the beginning of the file. - // We don't care about the inefficiency of the code, since this is a seldom case. + // Look for an ID3v2 tag until reaching the first valid MPEG frame. - const long tagOffset = find(headerID); - if(tagOffset < 0) - return -1; + ByteVector frameSyncBytes(2, '\0'); + ByteVector tagHeaderBytes(3, '\0'); + long position = 0; - const long frameOffset = firstFrameOffset(); - if(frameOffset < tagOffset) - return -1; + while(true) { + seek(position); + const ByteVector buffer = readBlock(bufferSize()); + if(buffer.isEmpty()) + return -1; - return tagOffset; + for(unsigned int i = 0; i < buffer.size(); ++i) { + frameSyncBytes[0] = frameSyncBytes[1]; + frameSyncBytes[1] = buffer[i]; + if(isFrameSync(frameSyncBytes)) { + const Header header(this, position + i - 1, true); + if(header.isValid()) + return -1; + } + + tagHeaderBytes[0] = tagHeaderBytes[1]; + tagHeaderBytes[1] = tagHeaderBytes[2]; + tagHeaderBytes[2] = buffer[i]; + if(tagHeaderBytes == headerID) + return position + i - 2; + } + + position += bufferSize(); + } } diff --git a/3rdparty/taglib/mpeg/mpegfile.h b/3rdparty/taglib/mpeg/mpegfile.h index e9e973879..2d2dff002 100644 --- a/3rdparty/taglib/mpeg/mpegfile.h +++ b/3rdparty/taglib/mpeg/mpegfile.h @@ -370,6 +370,15 @@ namespace TagLib { */ bool hasAPETag() const; + /*! + * Returns whether or not the given \a stream can be opened as an MPEG + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/mpeg/mpegheader.cpp b/3rdparty/taglib/mpeg/mpegheader.cpp index e678f15bf..5a5015d61 100644 --- a/3rdparty/taglib/mpeg/mpegheader.cpp +++ b/3rdparty/taglib/mpeg/mpegheader.cpp @@ -182,7 +182,7 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) // Check for the MPEG synch bytes. - if(!firstSyncByte(data[0]) || !secondSynchByte(data[1])) { + if(!isFrameSync(data)) { debug("MPEG::Header::parse() -- MPEG header did not match MPEG synch."); return; } @@ -197,10 +197,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->version = Version2; else if(versionBits == 3) d->version = Version1; - else { - debug("MPEG::Header::parse() -- Invalid MPEG version bits."); + else return; - } // Set the MPEG layer @@ -212,10 +210,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->layer = 2; else if(layerBits == 3) d->layer = 1; - else { - debug("MPEG::Header::parse() -- Invalid MPEG layer bits."); + else return; - } d->protectionEnabled = (static_cast(data[1] & 0x01) == 0); @@ -244,10 +240,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex]; - if(d->bitrate == 0) { - debug("MPEG::Header::parse() -- Invalid bit rate."); + if(d->bitrate == 0) return; - } // Set the sample rate @@ -264,7 +258,6 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->sampleRate = sampleRates[d->version][samplerateIndex]; if(d->sampleRate == 0) { - debug("MPEG::Header::parse() -- Invalid sample rate."); return; } @@ -311,20 +304,16 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) file->seek(offset + d->frameLength); const ByteVector nextData = file->readBlock(4); - if(nextData.size() < 4) { - debug("MPEG::Header::parse() -- Could not read the next frame header."); + if(nextData.size() < 4) return; - } const unsigned int HeaderMask = 0xfffe0c00; const unsigned int header = data.toUInt(0, true) & HeaderMask; const unsigned int nextHeader = nextData.toUInt(0, true) & HeaderMask; - if(header != nextHeader) { - debug("MPEG::Header::parse() -- The next frame was not consistent with this frame."); + if(header != nextHeader) return; - } } // Now that we're done parsing, set this to be a valid frame. diff --git a/3rdparty/taglib/mpeg/mpegproperties.cpp b/3rdparty/taglib/mpeg/mpegproperties.cpp index 6e7bb8232..d8b7bd506 100644 --- a/3rdparty/taglib/mpeg/mpegproperties.cpp +++ b/3rdparty/taglib/mpeg/mpegproperties.cpp @@ -157,23 +157,13 @@ void MPEG::Properties::read(File *file) { // Only the first valid frame is required if we have a VBR header. - long firstFrameOffset = file->firstFrameOffset(); + const long firstFrameOffset = file->firstFrameOffset(); if(firstFrameOffset < 0) { debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream."); return; } - Header firstHeader(file, firstFrameOffset); - - while(!firstHeader.isValid()) { - firstFrameOffset = file->nextFrameOffset(firstFrameOffset + 1); - if(firstFrameOffset < 0) { - debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); - return; - } - - firstHeader = Header(file, firstFrameOffset); - } + const Header firstHeader(file, firstFrameOffset, false); // Check for a VBR header that will help us in gathering information about a // VBR stream. @@ -207,24 +197,13 @@ void MPEG::Properties::read(File *file) // Look for the last MPEG audio frame to calculate the stream length. - long lastFrameOffset = file->lastFrameOffset(); + const long lastFrameOffset = file->lastFrameOffset(); if(lastFrameOffset < 0) { debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream."); return; } - Header lastHeader(file, lastFrameOffset, false); - - while(!lastHeader.isValid()) { - lastFrameOffset = file->previousFrameOffset(lastFrameOffset); - if(lastFrameOffset < 0) { - debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream."); - return; - } - - lastHeader = Header(file, lastFrameOffset, false); - } - + const Header lastHeader(file, lastFrameOffset, false); const long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength(); if(streamLength > 0) d->length = static_cast(streamLength * 8.0 / d->bitrate + 0.5); diff --git a/3rdparty/taglib/mpeg/mpegutils.h b/3rdparty/taglib/mpeg/mpegutils.h index e35f752fb..31b45a43b 100644 --- a/3rdparty/taglib/mpeg/mpegutils.h +++ b/3rdparty/taglib/mpeg/mpegutils.h @@ -41,17 +41,17 @@ namespace TagLib * MPEG frames can be recognized by the bit pattern 11111111 111, so the * first byte is easy to check for, however checking to see if the second byte * starts with \e 111 is a bit more tricky, hence these functions. + * + * \note This does not check the length of the vector, since this is an + * internal utility function. */ - inline bool firstSyncByte(unsigned char byte) + inline bool isFrameSync(const ByteVector &bytes, unsigned int offset = 0) { - return (byte == 0xFF); - } + // 0xFF in the second byte is possible in theory, but it's very unlikely. - inline bool secondSynchByte(unsigned char byte) - { - // 0xFF is possible in theory, but it's very unlikely be a header. - - return (byte != 0xFF && ((byte & 0xE0) == 0xE0)); + const unsigned char b1 = bytes[offset + 0]; + const unsigned char b2 = bytes[offset + 1]; + return (b1 == 0xFF && b2 != 0xFF && (b2 & 0xE0) == 0xE0); } } diff --git a/3rdparty/taglib/ogg/flac/oggflacfile.cpp b/3rdparty/taglib/ogg/flac/oggflacfile.cpp index 3a36ebe86..53d04508a 100644 --- a/3rdparty/taglib/ogg/flac/oggflacfile.cpp +++ b/3rdparty/taglib/ogg/flac/oggflacfile.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "oggflacfile.h" @@ -65,22 +66,36 @@ public: int commentPacket; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +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); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// Ogg::FLAC::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(file) + Properties::ReadStyle propertiesStyle) : + Ogg::File(file), + d(new FilePrivate()) { - d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Ogg::FLAC::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(stream) + Properties::ReadStyle propertiesStyle) : + Ogg::File(stream), + d(new FilePrivate()) { - d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } @@ -172,7 +187,7 @@ void Ogg::FLAC::File::read(bool readProperties, Properties::ReadStyle properties if(d->hasXiphComment) d->comment = new Ogg::XiphComment(xiphCommentData()); else - d->comment = new Ogg::XiphComment; + d->comment = new Ogg::XiphComment(); if(readProperties) diff --git a/3rdparty/taglib/ogg/flac/oggflacfile.h b/3rdparty/taglib/ogg/flac/oggflacfile.h index 28b3f67f8..b2686e457 100644 --- a/3rdparty/taglib/ogg/flac/oggflacfile.h +++ b/3rdparty/taglib/ogg/flac/oggflacfile.h @@ -127,9 +127,6 @@ namespace TagLib { /*! * Save the file. This will primarily save and update the XiphComment. * Returns true if the save is successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. It leads to a segfault. */ virtual bool save(); @@ -146,6 +143,14 @@ namespace TagLib { */ bool hasXiphComment() const; + /*! + * Check if the given \a stream can be opened as an Ogg FLAC file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/ogg/oggfile.cpp b/3rdparty/taglib/ogg/oggfile.cpp index 86b0b0764..c36e4d46c 100644 --- a/3rdparty/taglib/ogg/oggfile.cpp +++ b/3rdparty/taglib/ogg/oggfile.cpp @@ -253,7 +253,7 @@ void Ogg::File::writePacket(unsigned int i, const ByteVector &packet) ByteVectorList packets = firstPage->packets(); packets[i - firstPage->firstPacketIndex()] = packet; - if(firstPage != lastPage && lastPage->packetCount() > 2) { + if(firstPage != lastPage && lastPage->packetCount() > 1) { ByteVectorList lastPagePackets = lastPage->packets(); lastPagePackets.erase(lastPagePackets.begin()); packets.append(lastPagePackets); diff --git a/3rdparty/taglib/ogg/oggpage.cpp b/3rdparty/taglib/ogg/oggpage.cpp index 75aea22a2..414d3d530 100644 --- a/3rdparty/taglib/ogg/oggpage.cpp +++ b/3rdparty/taglib/ogg/oggpage.cpp @@ -208,15 +208,15 @@ List Ogg::Page::paginate(const ByteVectorList &packets, static const unsigned int SplitSize = 32 * 255; - // Force repagination if the packets are too large for a page. + // Force repagination if the segment table will exceed the size limit. if(strategy != Repaginate) { - size_t totalSize = packets.size(); + size_t tableSize = 0; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) - totalSize += it->size(); + tableSize += it->size() / 255 + 1; - if(totalSize > 255 * 255) + if(tableSize > 255) strategy = Repaginate; } diff --git a/3rdparty/taglib/ogg/opus/opusfile.cpp b/3rdparty/taglib/ogg/opus/opusfile.cpp index 43c102d07..d4f191ad1 100644 --- a/3rdparty/taglib/ogg/opus/opusfile.cpp +++ b/3rdparty/taglib/ogg/opus/opusfile.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "opusfile.h" @@ -53,6 +54,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +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); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -101,7 +114,7 @@ Opus::Properties *Opus::File::audioProperties() const bool Opus::File::save() { if(!d->comment) - d->comment = new Ogg::XiphComment; + d->comment = new Ogg::XiphComment(); setPacket(1, ByteVector("OpusTags", 8) + d->comment->render(false)); diff --git a/3rdparty/taglib/ogg/opus/opusfile.h b/3rdparty/taglib/ogg/opus/opusfile.h index 0363b5846..0e094eae8 100644 --- a/3rdparty/taglib/ogg/opus/opusfile.h +++ b/3rdparty/taglib/ogg/opus/opusfile.h @@ -110,12 +110,18 @@ namespace TagLib { * Save the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. It leads to a segfault. */ virtual bool save(); + /*! + * Returns whether or not the given \a stream can be opened as an Opus + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/ogg/speex/speexfile.cpp b/3rdparty/taglib/ogg/speex/speexfile.cpp index 2d374aedc..b3c8a6362 100644 --- a/3rdparty/taglib/ogg/speex/speexfile.cpp +++ b/3rdparty/taglib/ogg/speex/speexfile.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "speexfile.h" @@ -53,6 +54,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +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); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -101,7 +114,7 @@ Speex::Properties *Speex::File::audioProperties() const bool Speex::File::save() { if(!d->comment) - d->comment = new Ogg::XiphComment; + d->comment = new Ogg::XiphComment(); setPacket(1, d->comment->render()); diff --git a/3rdparty/taglib/ogg/speex/speexfile.h b/3rdparty/taglib/ogg/speex/speexfile.h index de38bfbfc..1be7113cb 100644 --- a/3rdparty/taglib/ogg/speex/speexfile.h +++ b/3rdparty/taglib/ogg/speex/speexfile.h @@ -110,12 +110,18 @@ namespace TagLib { * Save the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. It leads to a segfault. */ virtual bool save(); + /*! + * Returns whether or not the given \a stream can be opened as a Speex + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp b/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp index 1e19e8629..b4f221ab1 100644 --- a/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp +++ b/3rdparty/taglib/ogg/vorbis/vorbisfile.cpp @@ -28,10 +28,10 @@ #include #include #include +#include #include "vorbisfile.h" - using namespace TagLib; class Vorbis::File::FilePrivate @@ -59,6 +59,18 @@ namespace TagLib { static const char vorbisCommentHeaderID[] = { 0x03, 'v', 'o', 'r', 'b', 'i', 's', 0 }; } +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool 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); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -109,7 +121,7 @@ bool Vorbis::File::save() ByteVector v(vorbisCommentHeaderID); if(!d->comment) - d->comment = new Ogg::XiphComment; + d->comment = new Ogg::XiphComment(); v.append(d->comment->render()); setPacket(1, v); diff --git a/3rdparty/taglib/ogg/vorbis/vorbisfile.h b/3rdparty/taglib/ogg/vorbis/vorbisfile.h index 48d9d7ca2..04c0c04ea 100644 --- a/3rdparty/taglib/ogg/vorbis/vorbisfile.h +++ b/3rdparty/taglib/ogg/vorbis/vorbisfile.h @@ -118,12 +118,17 @@ namespace TagLib { * Save the file. * * This returns true if the save was successful. - * - * \warning In the current implementation, it's dangerous to call save() - * repeatedly. It leads to a segfault. */ virtual bool save(); + /*! + * Check if the given \a stream can be opened as an Ogg Vorbis file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/ogg/xiphcomment.cpp b/3rdparty/taglib/ogg/xiphcomment.cpp index db46aecb7..f56bf810c 100644 --- a/3rdparty/taglib/ogg/xiphcomment.cpp +++ b/3rdparty/taglib/ogg/xiphcomment.cpp @@ -261,10 +261,14 @@ bool Ogg::XiphComment::checkKey(const String &key) { if(key.size() < 1) return false; - for(String::ConstIterator it = key.begin(); it != key.end(); it++) - // forbid non-printable, non-ascii, '=' (#61) and '~' (#126) - if (*it < 32 || *it >= 128 || *it == 61 || *it == 126) + + // A key may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. + + for(String::ConstIterator it = key.begin(); it != key.end(); it++) { + if(*it < 0x20 || *it > 0x7D || *it == 0x3D) return false; + } + return true; } @@ -275,11 +279,18 @@ String Ogg::XiphComment::vendorID() const void Ogg::XiphComment::addField(const String &key, const String &value, bool replace) { + if(!checkKey(key)) { + debug("Ogg::XiphComment::addField() - Invalid key. Field not added."); + return; + } + + const String upperKey = key.upper(); + if(replace) - removeFields(key.upper()); + removeFields(upperKey); if(!key.isEmpty() && !value.isEmpty()) - d->fieldListMap[key.upper()].append(value); + d->fieldListMap[upperKey].append(value); } void Ogg::XiphComment::removeField(const String &key, const String &value) @@ -436,85 +447,69 @@ void Ogg::XiphComment::parse(const ByteVector &data) const unsigned int commentLength = data.toUInt(pos, false); pos += 4; - ByteVector entry = data.mid(pos, commentLength); - + const ByteVector entry = data.mid(pos, commentLength); pos += commentLength; // Don't go past data end + if(pos > data.size()) break; - // Handle Pictures separately - if(entry.startsWith("METADATA_BLOCK_PICTURE=")) { - - // We need base64 encoded data including padding - if((entry.size() - 23) > 3 && ((entry.size() - 23) % 4) == 0) { - - // Decode base64 picture data - ByteVector picturedata = ByteVector::fromBase64(entry.mid(23)); - if(picturedata.size()) { - - // Decode Flac Picture - FLAC::Picture * picture = new FLAC::Picture(); - if(picture->parse(picturedata)) { - - d->pictureList.append(picture); - - // continue to next field - continue; - } - else { - delete picture; - debug("Failed to decode FlacPicture block"); - } - } - else { - debug("Failed to decode base64 encoded data"); - } - } - else { - debug("Invalid base64 encoded data"); - } - } - - // Handle old picture standard - if(entry.startsWith("COVERART=")) { - - if((entry.size() - 9) > 3 && ((entry.size() - 9) % 4) == 0) { - - // Decode base64 picture data - ByteVector picturedata = ByteVector::fromBase64(entry.mid(9)); - if (picturedata.size()) { - - // Assume it's some type of image file - FLAC::Picture * picture = new FLAC::Picture(); - picture->setData(picturedata); - picture->setMimeType("image/"); - picture->setType(FLAC::Picture::Other); - d->pictureList.append(picture); - - // continue to next field - continue; - } - else { - debug("Failed to decode base64 encoded data"); - } - } - else { - debug("Invalid base64 encoded data"); - } - } - // Check for field separator - int sep = entry.find('='); + + const int sep = entry.find('='); if(sep < 1) { - debug("Discarding invalid comment field."); + debug("Ogg::XiphComment::parse() - Discarding a field. Separator not found."); continue; } - // Parse key and value - String key = String(entry.mid(0, sep), String::UTF8); - String value = String(entry.mid(sep + 1), String::UTF8); - addField(key, value, false); + // Parse the key + + const String key = String(entry.mid(0, sep), String::UTF8).upper(); + if(!checkKey(key)) { + debug("Ogg::XiphComment::parse() - Discarding a field. Invalid key."); + continue; + } + + if(key == "METADATA_BLOCK_PICTURE" || key == "COVERART") { + + // Handle Pictures separately + + const ByteVector picturedata = ByteVector::fromBase64(entry.mid(sep + 1)); + if(picturedata.isEmpty()) { + debug("Ogg::XiphComment::parse() - Discarding a field. Invalid base64 data"); + continue; + } + + if(key[0] == L'M') { + + // Decode FLAC Picture + + FLAC::Picture * picture = new FLAC::Picture(); + if(picture->parse(picturedata)) { + d->pictureList.append(picture); + } + else { + delete picture; + debug("Ogg::XiphComment::parse() - Failed to decode FLAC Picture block"); + } + } + else { + + // Assume it's some type of image file + + FLAC::Picture * picture = new FLAC::Picture(); + picture->setData(picturedata); + picture->setMimeType("image/"); + picture->setType(FLAC::Picture::Other); + d->pictureList.append(picture); + } + } + else { + + // Parse the text + + addField(key, String(entry.mid(sep + 1), String::UTF8), false); + } } } diff --git a/3rdparty/taglib/riff/aiff/aifffile.cpp b/3rdparty/taglib/riff/aiff/aifffile.cpp index 1a29938ce..4f9c868e6 100644 --- a/3rdparty/taglib/riff/aiff/aifffile.cpp +++ b/3rdparty/taglib/riff/aiff/aifffile.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "aifffile.h" @@ -53,6 +54,18 @@ public: bool hasID3v2; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool RIFF::AIFF::File::isSupported(IOStream *stream) +{ + // An AIFF file has to start with "FORM????AIFF" or "FORM????AIFC". + + const ByteVector id = Utils::readHeader(stream, 12, false); + return (id.startsWith("FORM") && (id.containsAt("AIFF", 8) || id.containsAt("AIFC", 8))); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/riff/aiff/aifffile.h b/3rdparty/taglib/riff/aiff/aifffile.h index a79d76b2b..5ba1a2791 100644 --- a/3rdparty/taglib/riff/aiff/aifffile.h +++ b/3rdparty/taglib/riff/aiff/aifffile.h @@ -126,6 +126,14 @@ namespace TagLib { */ bool hasID3v2Tag() const; + /*! + * Check if the given \a stream can be opened as an AIFF file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/riff/rifffile.cpp b/3rdparty/taglib/riff/rifffile.cpp index f9d33e10d..0af4d4b42 100644 --- a/3rdparty/taglib/riff/rifffile.cpp +++ b/3rdparty/taglib/riff/rifffile.cpp @@ -95,13 +95,13 @@ unsigned int RIFF::File::riffSize() const unsigned int RIFF::File::chunkCount() const { - return d->chunks.size(); + return static_cast(d->chunks.size()); } unsigned int RIFF::File::chunkDataSize(unsigned int i) const { if(i >= d->chunks.size()) { - debug("RIFF::File::chunkPadding() - Index out of range. Returning 0."); + debug("RIFF::File::chunkDataSize() - Index out of range. Returning 0."); return 0; } @@ -111,7 +111,7 @@ unsigned int RIFF::File::chunkDataSize(unsigned int i) const unsigned int RIFF::File::chunkOffset(unsigned int i) const { if(i >= d->chunks.size()) { - debug("RIFF::File::chunkPadding() - Index out of range. Returning 0."); + debug("RIFF::File::chunkOffset() - Index out of range. Returning 0."); return 0; } @@ -161,19 +161,19 @@ void RIFF::File::setChunkData(unsigned int i, const ByteVector &data) std::vector::iterator it = d->chunks.begin(); std::advance(it, i); - const int originalSize = it->size + it->padding; + const long long originalSize = static_cast(it->size) + it->padding; writeChunk(it->name, data, it->offset - 8, it->size + it->padding + 8); it->size = data.size(); - it->padding = data.size() % 1; + it->padding = data.size() % 2; - const int diff = it->size + it->padding - originalSize; + const long long diff = static_cast(it->size) + it->padding - originalSize; // Now update the internal offsets for(++it; it != d->chunks.end(); ++it) - it->offset += diff; + it->offset += static_cast(diff); // Update the global size. @@ -187,7 +187,7 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data) void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate) { - if(d->chunks.size() == 0) { + if(d->chunks.empty()) { debug("RIFF::File::setChunkData - No valid chunks found."); return; } @@ -269,7 +269,7 @@ void RIFF::File::removeChunk(unsigned int i) void RIFF::File::removeChunk(const ByteVector &name) { - for(int i = d->chunks.size() - 1; i >= 0; --i) { + for(int i = static_cast(d->chunks.size()) - 1; i >= 0; --i) { if(d->chunks[i].name == name) removeChunk(i); } @@ -292,7 +292,6 @@ void RIFF::File::read() d->size = readBlock(4).toUInt(bigEndian); offset += 8; - seek(offset); // + 8: chunk header at least, fix for additional junk bytes while(offset + 8 <= length()) { @@ -307,28 +306,24 @@ void RIFF::File::read() break; } - if(static_cast(tell()) + chunkSize > length()) { + if(static_cast(offset) + 8 + chunkSize > length()) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)"); setValid(false); break; } - offset += 8; - Chunk chunk; - chunk.name = chunkName; - chunk.size = chunkSize; - chunk.offset = offset; + chunk.name = chunkName; + chunk.size = chunkSize; + chunk.offset = offset + 8; + chunk.padding = 0; - offset += chunk.size; - - seek(offset); + offset = chunk.offset + chunk.size; // Check padding - chunk.padding = 0; - if(offset & 1) { + seek(offset); const ByteVector iByte = readBlock(1); if(iByte.size() == 1 && iByte[0] == '\0') { chunk.padding = 1; diff --git a/3rdparty/taglib/riff/wav/wavfile.cpp b/3rdparty/taglib/riff/wav/wavfile.cpp index 79ff91675..0ebe21c32 100644 --- a/3rdparty/taglib/riff/wav/wavfile.cpp +++ b/3rdparty/taglib/riff/wav/wavfile.cpp @@ -23,10 +23,11 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include "tbytevector.h" -#include "tdebug.h" -#include "tstringlist.h" -#include "tpropertymap.h" +#include +#include +#include +#include +#include #include "wavfile.h" #include "id3v2tag.h" @@ -60,6 +61,18 @@ public: bool hasInfo; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool RIFF::WAV::File::isSupported(IOStream *stream) +{ + // A WAV file has to start with "RIFF????WAVE". + + const ByteVector id = Utils::readHeader(stream, 12, false); + return (id.startsWith("RIFF") && id.containsAt("WAVE", 8)); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/riff/wav/wavfile.h b/3rdparty/taglib/riff/wav/wavfile.h index 80f17a852..f6c190ed6 100644 --- a/3rdparty/taglib/riff/wav/wavfile.h +++ b/3rdparty/taglib/riff/wav/wavfile.h @@ -175,6 +175,15 @@ namespace TagLib { */ bool hasInfoTag() const; + /*! + * Returns whether or not the given \a stream can be opened as a WAV + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/s3m/s3mproperties.cpp b/3rdparty/taglib/s3m/s3mproperties.cpp index 69654b1a4..e3e443cb8 100644 --- a/3rdparty/taglib/s3m/s3mproperties.cpp +++ b/3rdparty/taglib/s3m/s3mproperties.cpp @@ -64,7 +64,7 @@ public: S3M::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), - d(new PropertiesPrivate) + d(new PropertiesPrivate()) { } diff --git a/3rdparty/taglib/taglib_config.h.cmake b/3rdparty/taglib/taglib_config.h.cmake index 5f0ee6cfd..915f130aa 100644 --- a/3rdparty/taglib/taglib_config.h.cmake +++ b/3rdparty/taglib/taglib_config.h.cmake @@ -1,6 +1,11 @@ /* taglib_config.h. Generated by cmake from taglib_config.h.cmake */ +#ifndef TAGLIB_TAGLIB_CONFIG_H +#define TAGLIB_TAGLIB_CONFIG_H + /* These values are no longer used. This file is present only for compatibility reasons. */ #define TAGLIB_WITH_ASF 1 #define TAGLIB_WITH_MP4 1 + +#endif diff --git a/3rdparty/taglib/tagunion.cpp b/3rdparty/taglib/tagunion.cpp index c10d72b29..64d786b9a 100644 --- a/3rdparty/taglib/tagunion.cpp +++ b/3rdparty/taglib/tagunion.cpp @@ -79,10 +79,9 @@ public: std::vector tags; }; -TagUnion::TagUnion(Tag *first, Tag *second, Tag *third) +TagUnion::TagUnion(Tag *first, Tag *second, Tag *third) : + d(new TagUnionPrivate()) { - d = new TagUnionPrivate; - d->tags[0] = first; d->tags[1] = second; d->tags[2] = third; diff --git a/3rdparty/taglib/tagutils.cpp b/3rdparty/taglib/tagutils.cpp index dc047040c..d6d924064 100644 --- a/3rdparty/taglib/tagutils.cpp +++ b/3rdparty/taglib/tagutils.cpp @@ -77,3 +77,29 @@ long Utils::findAPE(File *file, long id3v1Location) return -1; } + +ByteVector TagLib::Utils::readHeader(IOStream *stream, unsigned int length, + bool skipID3v2, long *headerOffset) +{ + if(!stream || !stream->isOpen()) + return ByteVector(); + + const long originalPosition = stream->tell(); + long bufferOffset = 0; + + if(skipID3v2) { + stream->seek(0); + const ByteVector data = stream->readBlock(ID3v2::Header::size()); + if(data.startsWith(ID3v2::Header::fileIdentifier())) + bufferOffset = ID3v2::Header(data).completeTagSize(); + } + + stream->seek(bufferOffset); + const ByteVector header = stream->readBlock(length); + stream->seek(originalPosition); + + if(headerOffset) + *headerOffset = bufferOffset; + + return header; +} diff --git a/3rdparty/taglib/tagutils.h b/3rdparty/taglib/tagutils.h index fb11d1e06..4488a32ba 100644 --- a/3rdparty/taglib/tagutils.h +++ b/3rdparty/taglib/tagutils.h @@ -30,9 +30,12 @@ #ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header +#include + namespace TagLib { class File; + class IOStream; namespace Utils { @@ -41,6 +44,9 @@ namespace TagLib { long findID3v2(File *file); long findAPE(File *file, long id3v1Location); + + ByteVector readHeader(IOStream *stream, unsigned int length, bool skipID3v2, + long *headerOffset = 0); } } diff --git a/3rdparty/taglib/toolkit/taglib.h b/3rdparty/taglib/toolkit/taglib.h index bd4886bd8..6b029974e 100644 --- a/3rdparty/taglib/toolkit/taglib.h +++ b/3rdparty/taglib/toolkit/taglib.h @@ -30,7 +30,7 @@ #define TAGLIB_MAJOR_VERSION 1 #define TAGLIB_MINOR_VERSION 11 -#define TAGLIB_PATCH_VERSION 0 +#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\"") @@ -115,7 +115,7 @@ namespace TagLib { * * \section installing Installing TagLib * - * Please see the TagLib website for the latest + * Please see the TagLib website for the latest * downloads. * * TagLib can be built using the CMake build system. TagLib installs a taglib-config and pkg-config file to @@ -160,11 +160,10 @@ namespace TagLib { * * Questions about TagLib should be directed to the TagLib mailing list, not directly to the author. * - * - TagLib Homepage + * - TagLib Homepage * - TagLib Mailing List (taglib-devel@kde.org) * - * \author Scott Wheeler et al. - * + * \author TagLib authors. */ #endif diff --git a/3rdparty/taglib/toolkit/tbytevector.cpp b/3rdparty/taglib/toolkit/tbytevector.cpp index 6494a448b..d272057f6 100644 --- a/3rdparty/taglib/toolkit/tbytevector.cpp +++ b/3rdparty/taglib/toolkit/tbytevector.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -63,7 +62,7 @@ int findChar( for(TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { if(*it == c) - return (it - dataBegin); + return static_cast(it - dataBegin); } return -1; @@ -105,7 +104,7 @@ int findVector( ++itPattern; if(itPattern == patternEnd) - return (it - dataBegin); + return static_cast(it - dataBegin); } } @@ -125,7 +124,7 @@ T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignifica T sum = 0; for(size_t i = 0; i < length; i++) { const size_t shift = (mostSignificantByteFirst ? length - 1 - i : i) * 8; - sum |= static_cast(static_cast(v[offset + i])) << shift; + sum |= static_cast(static_cast(v[static_cast(offset + i)])) << shift; } return sum; @@ -176,7 +175,7 @@ TFloat toFloat(const ByteVector &v, size_t offset) } tmp; ::memcpy(&tmp, v.data() + offset, sizeof(TInt)); - if(ENDIAN != Utils::floatByteOrder()) + if(ENDIAN != Utils::systemByteOrder()) tmp.i = Utils::byteSwap(tmp.i); return tmp.f; @@ -191,7 +190,7 @@ ByteVector fromFloat(TFloat value) } tmp; tmp.f = value; - if(ENDIAN != Utils::floatByteOrder()) + if(ENDIAN != Utils::systemByteOrder()) tmp.i = Utils::byteSwap(tmp.i); return ByteVector(reinterpret_cast(&tmp), sizeof(TInt)); @@ -300,7 +299,7 @@ ByteVector ByteVector::null; ByteVector ByteVector::fromCString(const char *s, unsigned int length) { if(length == 0xffffffff) - return ByteVector(s, ::strlen(s)); + return ByteVector(s, static_cast(::strlen(s))); else return ByteVector(s, length); } @@ -375,7 +374,7 @@ ByteVector::ByteVector(const char *data, unsigned int length) : } ByteVector::ByteVector(const char *data) : - d(new ByteVectorPrivate(data, ::strlen(data))) + d(new ByteVectorPrivate(data, static_cast(::strlen(data)))) { } @@ -485,46 +484,60 @@ ByteVector &ByteVector::replace(char oldByte, char newByte) ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &with) { - // TODO: This takes O(n!) time in the worst case. Rewrite it to run in O(n) time. - - if(pattern.size() == 0 || pattern.size() > size()) - return *this; - if(pattern.size() == 1 && with.size() == 1) return replace(pattern[0], with[0]); - const size_t withSize = with.size(); - const size_t patternSize = pattern.size(); - const ptrdiff_t diff = withSize - patternSize; + // Check if there is at least one occurrence of the pattern. - size_t offset = 0; - while (true) { - offset = find(pattern, offset); - if(offset == static_cast(-1)) // Use npos in taglib2. - break; + int offset = find(pattern, 0); + if(offset == -1) + return *this; + + if(pattern.size() == with.size()) { + + // We think this case might be common enough to optimize it. detach(); + do + { + ::memcpy(data() + offset, with.data(), with.size()); + offset = find(pattern, offset + pattern.size()); + } while(offset != -1); + } + else { - if(diff < 0) { - ::memmove( - data() + offset + withSize, - data() + offset + patternSize, - size() - offset - patternSize); - resize(size() + diff); - } - else if(diff > 0) { - resize(size() + diff); - ::memmove( - data() + offset + withSize, - data() + offset + patternSize, - size() - diff - offset - patternSize); + // Loop once to calculate the result size. + + unsigned int dstSize = size(); + do + { + dstSize += with.size() - pattern.size(); + offset = find(pattern, offset + pattern.size()); + } while(offset != -1); + + // Loop again to copy modified data to the new vector. + + ByteVector dst(dstSize); + int dstOffset = 0; + + offset = 0; + while(true) { + const int next = find(pattern, offset); + if(next == -1) { + ::memcpy(dst.data() + dstOffset, data() + offset, size() - offset); + break; + } + + ::memcpy(dst.data() + dstOffset, data() + offset, next - offset); + dstOffset += next - offset; + + ::memcpy(dst.data() + dstOffset, with.data(), with.size()); + dstOffset += with.size(); + + offset = next + pattern.size(); } - ::memcpy(data() + offset, with.data(), with.size()); - - offset += withSize; - if(offset > size() - patternSize) - break; + swap(dst); } return *this; @@ -963,7 +976,7 @@ ByteVector ByteVector::fromBase64(const ByteVector & input) // Only return output if we processed all bytes if(len == 0) { - output.resize(dst - (unsigned char*) output.data()); + output.resize(static_cast(dst - (unsigned char*) output.data())); return output; } return ByteVector(); diff --git a/3rdparty/taglib/toolkit/tbytevectorstream.cpp b/3rdparty/taglib/toolkit/tbytevectorstream.cpp index 5e200b3d7..333f528c1 100644 --- a/3rdparty/taglib/toolkit/tbytevectorstream.cpp +++ b/3rdparty/taglib/toolkit/tbytevectorstream.cpp @@ -53,9 +53,9 @@ ByteVectorStream::ByteVectorStreamPrivate::ByteVectorStreamPrivate(const ByteVec // public members //////////////////////////////////////////////////////////////////////////////// -ByteVectorStream::ByteVectorStream(const ByteVector &data) +ByteVectorStream::ByteVectorStream(const ByteVector &data) : + d(new ByteVectorStreamPrivate(data)) { - d = new ByteVectorStreamPrivate(data); } ByteVectorStream::~ByteVectorStream() @@ -137,7 +137,7 @@ void ByteVectorStream::seek(long offset, Position p) d->position += offset; break; case End: - d->position = length() - offset; + d->position = length() + offset; // offset is expected to be negative break; } } diff --git a/3rdparty/taglib/toolkit/tdebug.cpp b/3rdparty/taglib/toolkit/tdebug.cpp index 557baed6e..b2efc4cb5 100644 --- a/3rdparty/taglib/toolkit/tdebug.cpp +++ b/3rdparty/taglib/toolkit/tdebug.cpp @@ -27,6 +27,8 @@ #include #endif +#if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) + #include "tdebug.h" #include "tstring.h" #include "tdebuglistener.h" @@ -43,27 +45,20 @@ namespace TagLib void debug(const String &s) { -#if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) - debugListener->printMessage("TagLib: " + s + "\n"); - -#endif } void debugData(const ByteVector &v) { -#if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) - - for(size_t i = 0; i < v.size(); ++i) - { - std::string bits = std::bitset<8>(v[i]).to_string(); - String msg = Utils::formatString( - "*** [%d] - char '%c' - int %d, 0x%02x, 0b%s\n", + for(unsigned int i = 0; i < v.size(); ++i) { + const std::string bits = std::bitset<8>(v[i]).to_string(); + const String msg = Utils::formatString( + "*** [%u] - char '%c' - int %d, 0x%02x, 0b%s\n", i, v[i], v[i], v[i], bits.c_str()); debugListener->printMessage(msg); } - -#endif } } + +#endif diff --git a/3rdparty/taglib/toolkit/tdebug.h b/3rdparty/taglib/toolkit/tdebug.h index bd94d159f..80d00d39e 100644 --- a/3rdparty/taglib/toolkit/tdebug.h +++ b/3rdparty/taglib/toolkit/tdebug.h @@ -32,10 +32,11 @@ namespace TagLib { class ByteVector; #ifndef DO_NOT_DOCUMENT +#if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) /*! - * A simple function that outputs the debug messages to the listener. - * The default listener redirects the messages to \a stderr when NDEBUG is + * A simple function that outputs the debug messages to the listener. + * The default listener redirects the messages to \a stderr when NDEBUG is * not defined. * * \warning Do not use this outside of TagLib, it could lead to undefined @@ -45,7 +46,7 @@ namespace TagLib { * \internal */ void debug(const String &s); - + /*! * For debugging binary data. * @@ -56,6 +57,13 @@ namespace TagLib { * \internal */ void debugData(const ByteVector &v); + +#else + + #define debug(x) ((void)0) + #define debugData(x) ((void)0) + +#endif } #endif diff --git a/3rdparty/taglib/toolkit/tfile.cpp b/3rdparty/taglib/toolkit/tfile.cpp index c634baa85..aff1684d9 100644 --- a/3rdparty/taglib/toolkit/tfile.cpp +++ b/3rdparty/taglib/toolkit/tfile.cpp @@ -69,39 +69,38 @@ using namespace TagLib; class File::FilePrivate { public: - FilePrivate(IOStream *stream, bool owner); + FilePrivate(IOStream *stream, bool owner) : + stream(stream), + streamOwner(owner), + valid(true) {} + + ~FilePrivate() + { + if(streamOwner) + delete stream; + } IOStream *stream; bool streamOwner; bool valid; }; -File::FilePrivate::FilePrivate(IOStream *stream, bool owner) : - stream(stream), - streamOwner(owner), - valid(true) -{ -} - //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -File::File(FileName fileName) +File::File(FileName fileName) : + d(new FilePrivate(new FileStream(fileName), true)) { - IOStream *stream = new FileStream(fileName); - d = new FilePrivate(stream, true); } -File::File(IOStream *stream) +File::File(IOStream *stream) : + d(new FilePrivate(stream, false)) { - d = new FilePrivate(stream, false); } File::~File() { - if(d->stream && d->streamOwner) - delete d->stream; delete d; } diff --git a/3rdparty/taglib/toolkit/tfile.h b/3rdparty/taglib/toolkit/tfile.h index a6dda7bad..55f53a521 100644 --- a/3rdparty/taglib/toolkit/tfile.h +++ b/3rdparty/taglib/toolkit/tfile.h @@ -86,7 +86,7 @@ namespace TagLib { * format, the returned 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 ID3v2 and an ID3v2 + * 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). * BIC: Will be made virtual in future releases. */ diff --git a/3rdparty/taglib/toolkit/tfilestream.cpp b/3rdparty/taglib/toolkit/tfilestream.cpp index 5205bae0b..17a09f3da 100644 --- a/3rdparty/taglib/toolkit/tfilestream.cpp +++ b/3rdparty/taglib/toolkit/tfilestream.cpp @@ -51,12 +51,11 @@ namespace { const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); - if(!path.wstr().empty()) - return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - else if(!path.str().empty()) - return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - else - return InvalidFileHandle; +#if defined (PLATFORM_WINRT) + return CreateFile2(path.wstr().c_str(), access, FILE_SHARE_READ, OPEN_EXISTING, NULL); +#else + return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); +#endif } void closeFile(FileHandle file) @@ -262,7 +261,7 @@ void FileStream::insert(const ByteVector &data, unsigned long start, unsigned lo // to overwrite. Appropriately increment the readPosition. seek(readPosition); - const size_t bytesRead = readFile(d->file, aboutToOverwrite); + const unsigned int bytesRead = static_cast(readFile(d->file, aboutToOverwrite)); aboutToOverwrite.resize(bytesRead); readPosition += bufferLength; @@ -305,10 +304,10 @@ void FileStream::removeBlock(unsigned long start, unsigned long length) ByteVector buffer(static_cast(bufferLength)); - for(size_t bytesRead = -1; bytesRead != 0;) + for(unsigned int bytesRead = -1; bytesRead != 0;) { seek(readPosition); - bytesRead = readFile(d->file, buffer); + bytesRead = static_cast(readFile(d->file, buffer)); readPosition += bytesRead; // Check to see if we just read the last block. We need to call clear() @@ -347,28 +346,17 @@ void FileStream::seek(long offset, Position p) #ifdef _WIN32 - DWORD whence; - switch(p) { - case Beginning: - whence = FILE_BEGIN; - break; - case Current: - whence = FILE_CURRENT; - break; - case End: - whence = FILE_END; - break; - default: + if(p != Beginning && p != Current && p != End) { debug("FileStream::seek() -- Invalid Position value."); return; } - SetLastError(NO_ERROR); - SetFilePointer(d->file, offset, NULL, whence); + LARGE_INTEGER liOffset; + liOffset.QuadPart = offset; - const int lastError = GetLastError(); - if(lastError != NO_ERROR && lastError != ERROR_NEGATIVE_SEEK) + if(!SetFilePointerEx(d->file, liOffset, NULL, static_cast(p))) { debug("FileStream::seek() -- Failed to set the file pointer."); + } #else @@ -410,10 +398,11 @@ long FileStream::tell() const { #ifdef _WIN32 - SetLastError(NO_ERROR); - const DWORD position = SetFilePointer(d->file, 0, NULL, FILE_CURRENT); - if(GetLastError() == NO_ERROR) { - return static_cast(position); + const LARGE_INTEGER zero = {}; + LARGE_INTEGER position; + + if(SetFilePointerEx(d->file, zero, &position, FILE_CURRENT) && position.QuadPart <= LONG_MAX) { + return static_cast(position.QuadPart); } else { debug("FileStream::tell() -- Failed to get the file pointer."); @@ -436,10 +425,10 @@ long FileStream::length() #ifdef _WIN32 - SetLastError(NO_ERROR); - const DWORD fileSize = GetFileSize(d->file, NULL); - if(GetLastError() == NO_ERROR) { - return static_cast(fileSize); + LARGE_INTEGER fileSize; + + if(GetFileSizeEx(d->file, &fileSize) && fileSize.QuadPart <= LONG_MAX) { + return static_cast(fileSize.QuadPart); } else { debug("FileStream::length() -- Failed to get the file size."); @@ -472,9 +461,7 @@ void FileStream::truncate(long length) seek(length); - SetLastError(NO_ERROR); - SetEndOfFile(d->file); - if(GetLastError() != NO_ERROR) { + if(!SetEndOfFile(d->file)) { debug("FileStream::truncate() -- Failed to truncate the file."); } diff --git a/3rdparty/taglib/toolkit/tiostream.cpp b/3rdparty/taglib/toolkit/tiostream.cpp index 72fe32a61..de0bd5053 100644 --- a/3rdparty/taglib/toolkit/tiostream.cpp +++ b/3rdparty/taglib/toolkit/tiostream.cpp @@ -23,73 +23,49 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#ifdef _WIN32 +# include +# include +#endif + #include "tiostream.h" using namespace TagLib; #ifdef _WIN32 -# include "tstring.h" -# include "tdebug.h" -# include - namespace { - // Check if the running system has CreateFileW() function. - // Windows9x systems don't have CreateFileW() or can't accept Unicode file names. - - bool supportsUnicode() + std::wstring ansiToUnicode(const char *str) { -#ifdef UNICODE - return true; -#else - const FARPROC p = GetProcAddress(GetModuleHandleA("kernel32"), "CreateFileW"); - return (p != NULL); -#endif - } - - // Indicates whether the system supports Unicode file names. - - const bool SystemSupportsUnicode = supportsUnicode(); - - // Converts a UTF-16 string into a local encoding. - // This function should only be used in Windows9x systems which don't support - // Unicode file names. - - std::string unicodeToAnsi(const wchar_t *wstr) - { - if(SystemSupportsUnicode) { - debug("unicodeToAnsi() - Should not be used on WinNT systems."); - } - - const int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); + const int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); if(len == 0) - return std::string(); + return std::wstring(); - std::string str(len, '\0'); - WideCharToMultiByte(CP_ACP, 0, wstr, -1, &str[0], len, NULL, NULL); + std::wstring wstr(len - 1, L'\0'); + MultiByteToWideChar(CP_ACP, 0, str, -1, &wstr[0], len); - return str; + return wstr; } } -// If WinNT, stores a Unicode string into m_wname directly. -// If Win9x, converts and stores it into m_name to avoid calling Unicode version functions. +// m_name is no longer used, but kept for backward compatibility. -FileName::FileName(const wchar_t *name) - : m_name (SystemSupportsUnicode ? "" : unicodeToAnsi(name)) - , m_wname(SystemSupportsUnicode ? name : L"") +FileName::FileName(const wchar_t *name) : + m_name(), + m_wname(name) { } -FileName::FileName(const char *name) - : m_name(name) +FileName::FileName(const char *name) : + m_name(), + m_wname(ansiToUnicode(name)) { } -FileName::FileName(const FileName &name) - : m_name (name.m_name) - , m_wname(name.m_wname) +FileName::FileName(const FileName &name) : + m_name(), + m_wname(name.m_wname) { } @@ -115,25 +91,9 @@ const std::string &FileName::str() const String FileName::toString() const { - if(!m_wname.empty()) { - return String(m_wname); - } - else if(!m_name.empty()) { - const int len = MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, NULL, 0); - if(len == 0) - return String(); - - std::vector buf(len); - MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, &buf[0], len); - - return String(&buf[0]); - } - else { - return String(); - } + return String(m_wname.c_str()); } - #endif // _WIN32 //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/toolkit/tlist.h b/3rdparty/taglib/toolkit/tlist.h index 6b4aa0a52..377b82481 100644 --- a/3rdparty/taglib/toolkit/tlist.h +++ b/3rdparty/taglib/toolkit/tlist.h @@ -229,6 +229,11 @@ namespace TagLib { */ List &operator=(const List &l); + /*! + * Exchanges the content of this list by the content of \a l. + */ + void swap(List &l); + /*! * Compares this list with \a l and returns true if all of the elements are * the same. diff --git a/3rdparty/taglib/toolkit/tlist.tcc b/3rdparty/taglib/toolkit/tlist.tcc index bf8b0007c..478f09834 100644 --- a/3rdparty/taglib/toolkit/tlist.tcc +++ b/3rdparty/taglib/toolkit/tlist.tcc @@ -89,9 +89,9 @@ public: //////////////////////////////////////////////////////////////////////////////// template -List::List() +List::List() : + d(new ListPrivate()) { - d = new ListPrivate; } template @@ -196,7 +196,7 @@ List &List::clear() template unsigned int List::size() const { - return d->list.size(); + return static_cast(d->list.size()); } template @@ -283,16 +283,18 @@ const T &List::operator[](unsigned int i) const template List &List::operator=(const List &l) { - if(&l == this) - return *this; - - if(d->deref()) - delete d; - d = l.d; - d->ref(); + List(l).swap(*this); return *this; } +template +void List::swap(List &l) +{ + using std::swap; + + swap(d, l.d); +} + template bool List::operator==(const List &l) const { diff --git a/3rdparty/taglib/toolkit/tmap.h b/3rdparty/taglib/toolkit/tmap.h index c24c76367..f54e5a2a9 100644 --- a/3rdparty/taglib/toolkit/tmap.h +++ b/3rdparty/taglib/toolkit/tmap.h @@ -174,6 +174,11 @@ namespace TagLib { */ Map &operator=(const Map &m); + /*! + * Exchanges the content of this map by the content of \a m. + */ + void swap(Map &m); + protected: /* * If this List is being shared via implicit sharing, do a deep copy of the diff --git a/3rdparty/taglib/toolkit/tmap.tcc b/3rdparty/taglib/toolkit/tmap.tcc index 68f0d311a..2e4ed5ebf 100644 --- a/3rdparty/taglib/toolkit/tmap.tcc +++ b/3rdparty/taglib/toolkit/tmap.tcc @@ -48,9 +48,9 @@ public: }; template -Map::Map() +Map::Map() : + d(new MapPrivate()) { - d = new MapPrivate; } template @@ -152,7 +152,7 @@ Map &Map::erase(const Key &key) template unsigned int Map::size() const { - return d->map.size(); + return static_cast(d->map.size()); } template @@ -171,16 +171,18 @@ T &Map::operator[](const Key &key) template Map &Map::operator=(const Map &m) { - if(&m == this) - return *this; - - if(d->deref()) - delete(d); - d = m.d; - d->ref(); + Map(m).swap(*this); return *this; } +template +void Map::swap(Map &m) +{ + using std::swap; + + swap(d, m.d); +} + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/toolkit/trefcounter.cpp b/3rdparty/taglib/toolkit/trefcounter.cpp index 27d17b834..6638fcaa5 100644 --- a/3rdparty/taglib/toolkit/trefcounter.cpp +++ b/3rdparty/taglib/toolkit/trefcounter.cpp @@ -31,14 +31,9 @@ #if defined(HAVE_STD_ATOMIC) # include -# define ATOMIC_INT std::atomic -# define ATOMIC_INC(x) x.fetch_add(1) -# define ATOMIC_DEC(x) (x.fetch_sub(1) - 1) -#elif defined(HAVE_BOOST_ATOMIC) -# include -# define ATOMIC_INT boost::atomic -# define ATOMIC_INC(x) x.fetch_add(1) -# define ATOMIC_DEC(x) (x.fetch_sub(1) - 1) +# define ATOMIC_INT std::atomic_int +# define ATOMIC_INC(x) (++x) +# define ATOMIC_DEC(x) (--x) #elif defined(HAVE_GCC_ATOMIC) # define ATOMIC_INT int # define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) diff --git a/3rdparty/taglib/toolkit/trefcounter.h b/3rdparty/taglib/toolkit/trefcounter.h index bc3cdd9be..db97c5385 100644 --- a/3rdparty/taglib/toolkit/trefcounter.h +++ b/3rdparty/taglib/toolkit/trefcounter.h @@ -30,6 +30,7 @@ #include "taglib.h" #ifdef __APPLE__ +# define OSATOMIC_DEPRECATED 0 # include # define TAGLIB_ATOMIC_MAC #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) diff --git a/3rdparty/taglib/toolkit/tstring.cpp b/3rdparty/taglib/toolkit/tstring.cpp index 01a69266b..c60a3e2ed 100644 --- a/3rdparty/taglib/toolkit/tstring.cpp +++ b/3rdparty/taglib/toolkit/tstring.cpp @@ -23,19 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -// This class assumes that std::basic_string has a contiguous and null-terminated buffer. - -#include #include #include -#include -#include -#ifdef _WIN32 -# include -#else -# include "unicode.h" -#endif +#include #include #include @@ -48,70 +39,6 @@ namespace { using namespace TagLib; - size_t UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) - { - size_t len = 0; - -#ifdef _WIN32 - - len = ::WideCharToMultiByte(CP_UTF8, 0, src, srcLength, dst, dstLength, NULL, NULL); - -#else - - using namespace Unicode; - - const UTF16 *srcBegin = src; - const UTF16 *srcEnd = srcBegin + srcLength; - - UTF8 *dstBegin = reinterpret_cast(dst); - UTF8 *dstEnd = dstBegin + dstLength; - - ConversionResult result = ConvertUTF16toUTF8( - &srcBegin, srcEnd, &dstBegin, dstEnd, lenientConversion); - - if(result == conversionOK) - len = dstBegin - reinterpret_cast(dst); - -#endif - - if(len == 0) - debug("String::UTF16toUTF8() - Unicode conversion error."); - - return len; - } - - size_t UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) - { - size_t len = 0; - -#ifdef _WIN32 - - len = ::MultiByteToWideChar(CP_UTF8, 0, src, srcLength, dst, dstLength); - -#else - - using namespace Unicode; - - const UTF8 *srcBegin = reinterpret_cast(src); - const UTF8 *srcEnd = srcBegin + srcLength; - - UTF16 *dstBegin = dst; - UTF16 *dstEnd = dstBegin + dstLength; - - ConversionResult result = ConvertUTF8toUTF16( - &srcBegin, srcEnd, &dstBegin, dstEnd, lenientConversion); - - if(result == conversionOK) - len = dstBegin - dst; - -#endif - - if(len == 0) - debug("String::UTF8toUTF16() - Unicode conversion error."); - - return len; - } - // Returns the native format of std::wstring. String::Type wcharByteOrder() { @@ -137,28 +64,61 @@ namespace { data.resize(length); - if(length > 0) { - const size_t len = UTF8toUTF16(s, length, &data[0], data.size()); - data.resize(len); + try { + const std::wstring::iterator dstEnd = utf8::utf8to16(s, s + length, data.begin()); + data.resize(dstEnd - data.begin()); } + catch(const utf8::exception &e) { + const String message(e.what()); + debug("String::copyFromUTF8() - UTF8-CPP error: " + message); + data.clear(); + } + } + + // Helper functions to read a UTF-16 character from an array. + template + unsigned short nextUTF16(const T **p); + + template <> + unsigned short nextUTF16(const wchar_t **p) + { + return static_cast(*(*p)++); + } + + template <> + unsigned short nextUTF16(const char **p) + { + union { + unsigned short w; + char c[2]; + } u; + u.c[0] = *(*p)++; + u.c[1] = *(*p)++; + return u.w; } // Converts a UTF-16 (with BOM), UTF-16LE or UTF16-BE string into // UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. - void copyFromUTF16(std::wstring &data, const wchar_t *s, size_t length, String::Type t) + template + void copyFromUTF16(std::wstring &data, const T *s, size_t length, String::Type t) { bool swap; if(t == String::UTF16) { - if(length >= 1 && s[0] == 0xfeff) - swap = false; // Same as CPU endian. No need to swap bytes. - else if(length >= 1 && s[0] == 0xfffe) - swap = true; // Not same as CPU endian. Need to swap bytes. - else { - debug("String::copyFromUTF16() - Invalid UTF16 string."); + if(length < 1) { + debug("String::copyFromUTF16() - Invalid UTF16 string. Too short to have a BOM."); + return; + } + + const unsigned short bom = nextUTF16(&s); + if(bom == 0xfeff) + swap = false; // Same as CPU endian. No need to swap bytes. + else if(bom == 0xfffe) + swap = true; // Not same as CPU endian. Need to swap bytes. + else { + debug("String::copyFromUTF16() - Invalid UTF16 string. BOM is broken."); return; } - s++; length--; } else { @@ -166,57 +126,12 @@ namespace } data.resize(length); - if(length > 0) { - if(swap) { - for(size_t i = 0; i < length; ++i) - data[i] = Utils::byteSwap(static_cast(s[i])); - } - else { - ::wmemcpy(&data[0], s, length); - } - } - } - - // Converts a UTF-16 (with BOM), UTF-16LE or UTF16-BE string into - // UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. - void copyFromUTF16(std::wstring &data, const char *s, size_t length, String::Type t) - { - bool swap; - if(t == String::UTF16) { - if(length < 2) { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. - unsigned short bom; - ::memcpy(&bom, s, 2); - - if(bom == 0xfeff) - swap = false; // Same as CPU endian. No need to swap bytes. - else if(bom == 0xfffe) - swap = true; // Not same as CPU endian. Need to swap bytes. - else { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - s += 2; - length -= 2; - } - else { - swap = (t != wcharByteOrder()); - } - - data.resize(length / 2); - for(size_t i = 0; i < length / 2; ++i) { - unsigned short c; - ::memcpy(&c, s, 2); + for(size_t i = 0; i < length; ++i) { + const unsigned short c = nextUTF16(&s); if(swap) - c = Utils::byteSwap(c); - - data[i] = static_cast(c); - s += 2; + data[i] = Utils::byteSwap(c); + else + data[i] = c; } } } @@ -229,10 +144,6 @@ public: StringPrivate() : RefCounter() {} - StringPrivate(unsigned int n, wchar_t c) : - RefCounter(), - data(static_cast(n), c) {} - /*! * Stores string in UTF-16. The byte order depends on the CPU endian. */ @@ -332,9 +243,13 @@ String::String(wchar_t c, Type t) : } String::String(char c, Type t) : - d(new StringPrivate(1, static_cast(c))) + d(new StringPrivate()) { - if(t != Latin1 && t != UTF8) { + if(t == Latin1) + copyFromLatin1(d->data, &c, 1); + else if(t == String::UTF8) + copyFromUTF8(d->data, &c, 1); + else { debug("String::String() -- char should not contain UTF16."); } } @@ -350,7 +265,7 @@ String::String(const ByteVector &v, Type t) : else if(t == UTF8) copyFromUTF8(d->data, v.data(), v.size()); else - copyFromUTF16(d->data, v.data(), v.size(), 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())); @@ -410,12 +325,12 @@ String::ConstIterator String::end() const int String::find(const String &s, int offset) const { - return d->data.find(s.d->data, offset); + return static_cast(d->data.find(s.d->data, offset)); } int String::rfind(const String &s, int offset) const { - return d->data.rfind(s.d->data, offset); + return static_cast(d->data.rfind(s.d->data, offset)); } StringList String::split(const String &separator) const @@ -445,7 +360,10 @@ bool String::startsWith(const String &s) const String String::substr(unsigned int position, unsigned int n) const { - return String(d->data.substr(position, n)); + if(position == 0 && n >= size()) + return *this; + else + return String(d->data.substr(position, n)); } String &String::append(const String &s) @@ -464,12 +382,11 @@ String & String::clear() String String::upper() const { String s; + s.d->data.reserve(size()); - static int shift = 'A' - 'a'; - - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); ++it) { + for(ConstIterator it = begin(); it != end(); ++it) { if(*it >= 'a' && *it <= 'z') - s.d->data.push_back(*it + shift); + s.d->data.push_back(*it + 'A' - 'a'); else s.d->data.push_back(*it); } @@ -479,7 +396,7 @@ String String::upper() const unsigned int String::size() const { - return d->data.size(); + return static_cast(d->data.size()); } unsigned int String::length() const @@ -506,25 +423,27 @@ ByteVector String::data(Type t) const ByteVector v(size(), 0); char *p = v.data(); - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) + for(ConstIterator it = begin(); it != end(); ++it) *p++ = static_cast(*it); return v; } case UTF8: - if(!d->data.empty()) { - ByteVector v(size() * 4 + 1, 0); + ByteVector v(size() * 4, 0); - const size_t len = UTF16toUTF8( - d->data.c_str(), d->data.size(), v.data(), v.size()); - v.resize(len); + try { + const ByteVector::Iterator dstEnd = utf8::utf16to8(begin(), end(), v.begin()); + v.resize(static_cast(dstEnd - v.begin())); + } + catch(const utf8::exception &e) { + const String message(e.what()); + debug("String::data() - UTF8-CPP error: " + message); + v.clear(); + } return v; } - else { - return ByteVector(); - } case UTF16: { ByteVector v(2 + size() * 2, 0); @@ -535,7 +454,7 @@ ByteVector String::data(Type t) const *p++ = '\xff'; *p++ = '\xfe'; - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + for(ConstIterator it = begin(); it != end(); ++it) { *p++ = static_cast(*it & 0xff); *p++ = static_cast(*it >> 8); } @@ -547,7 +466,7 @@ ByteVector String::data(Type t) const ByteVector v(size() * 2, 0); char *p = v.data(); - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + for(ConstIterator it = begin(); it != end(); ++it) { *p++ = static_cast(*it >> 8); *p++ = static_cast(*it & 0xff); } @@ -559,7 +478,7 @@ ByteVector String::data(Type t) const ByteVector v(size() * 2, 0); char *p = v.data(); - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + for(ConstIterator it = begin(); it != end(); ++it) { *p++ = static_cast(*it & 0xff); *p++ = static_cast(*it >> 8); } @@ -604,12 +523,12 @@ String String::stripWhiteSpace() const return String(); const size_t pos2 = d->data.find_last_not_of(WhiteSpaceChars); - return substr(pos1, pos2 - pos1 + 1); + return substr(static_cast(pos1), static_cast(pos2 - pos1 + 1)); } bool String::isLatin1() const { - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + for(ConstIterator it = begin(); it != end(); ++it) { if(*it >= 256) return false; } @@ -618,7 +537,7 @@ bool String::isLatin1() const bool String::isAscii() const { - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + for(ConstIterator it = begin(); it != end(); ++it) { if(*it >= 128) return false; } @@ -787,6 +706,12 @@ void String::detach() if(d->count() > 1) String(d->data.c_str()).swap(*this); } + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +const String::Type String::WCharByteOrder = wcharByteOrder(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/toolkit/tstring.h b/3rdparty/taglib/toolkit/tstring.h index 97e9ff66e..b1be04b8c 100644 --- a/3rdparty/taglib/toolkit/tstring.h +++ b/3rdparty/taglib/toolkit/tstring.h @@ -536,6 +536,13 @@ namespace TagLib { void detach(); private: + /*! + * \deprecated This variable is no longer used, but NEVER remove this. It + * may lead to a linkage error. + */ + // BIC: remove + static const Type WCharByteOrder; + class StringPrivate; StringPrivate *d; }; diff --git a/3rdparty/taglib/toolkit/tutils.h b/3rdparty/taglib/toolkit/tutils.h index e3e4f6c36..6d96cd12d 100644 --- a/3rdparty/taglib/toolkit/tutils.h +++ b/3rdparty/taglib/toolkit/tutils.h @@ -34,9 +34,7 @@ # include #endif -#if defined(HAVE_BOOST_BYTESWAP) -# include -#elif defined(HAVE_MSC_BYTESWAP) +#if defined(HAVE_MSC_BYTESWAP) # include #elif defined(HAVE_GLIBC_BYTESWAP) # include @@ -63,11 +61,7 @@ namespace TagLib */ inline unsigned short byteSwap(unsigned short x) { -#if defined(HAVE_BOOST_BYTESWAP) - - return boost::endian::endian_reverse(static_cast(x)); - -#elif defined(HAVE_GCC_BYTESWAP) +#if defined(HAVE_GCC_BYTESWAP) return __builtin_bswap16(x); @@ -99,11 +93,7 @@ namespace TagLib */ inline unsigned int byteSwap(unsigned int x) { -#if defined(HAVE_BOOST_BYTESWAP) - - return boost::endian::endian_reverse(static_cast(x)); - -#elif defined(HAVE_GCC_BYTESWAP) +#if defined(HAVE_GCC_BYTESWAP) return __builtin_bswap32(x); @@ -138,11 +128,7 @@ namespace TagLib */ inline unsigned long long byteSwap(unsigned long long x) { -#if defined(HAVE_BOOST_BYTESWAP) - - return boost::endian::endian_reverse(static_cast(x)); - -#elif defined(HAVE_GCC_BYTESWAP) +#if defined(HAVE_GCC_BYTESWAP) return __builtin_bswap64(x); @@ -221,23 +207,6 @@ namespace TagLib return String(); } - /*! - * Returns whether the two strings s1 and s2 are equal, ignoring the case of - * the characters. - * - * We took the trouble to define this one here, since there are some - * incompatible variations of case insensitive strcmp(). - */ - inline bool equalsIgnoreCase(const char *s1, const char *s2) - { - while(*s1 != '\0' && *s2 != '\0' && ::tolower(*s1) == ::tolower(*s2)) { - s1++; - s2++; - } - - return (*s1 == '\0' && *s2 == '\0'); - } - /*! * The types of byte order of the running system. */ @@ -250,7 +219,7 @@ namespace TagLib }; /*! - * Returns the integer byte order of the system. + * Returns the byte order of the system. */ inline ByteOrder systemByteOrder() { @@ -265,26 +234,6 @@ namespace TagLib else return BigEndian; } - - /*! - * Returns the IEEE754 byte order of the system. - */ - inline ByteOrder floatByteOrder() - { - union { - double d; - char c; - } u; - - // 1.0 is stored in memory like 0x3FF0000000000000 in canonical form. - // So the first byte is zero if little endian. - - u.d = 1.0; - if(u.c == 0) - return LittleEndian; - else - return BigEndian; - } } } } diff --git a/3rdparty/taglib/toolkit/tzlib.cpp b/3rdparty/taglib/toolkit/tzlib.cpp index 40158fd2e..6d07ba3d2 100644 --- a/3rdparty/taglib/toolkit/tzlib.cpp +++ b/3rdparty/taglib/toolkit/tzlib.cpp @@ -27,23 +27,19 @@ # include #endif -#if defined(HAVE_ZLIB) +#ifdef HAVE_ZLIB # include -#elif defined(HAVE_BOOST_ZLIB) -# include -# include +# include +# include #endif -#include -#include - #include "tzlib.h" using namespace TagLib; bool zlib::isAvailable() { -#if defined(HAVE_ZLIB) || defined(HAVE_BOOST_ZLIB) +#ifdef HAVE_ZLIB return true; @@ -56,7 +52,7 @@ bool zlib::isAvailable() ByteVector zlib::decompress(const ByteVector &data) { -#if defined(HAVE_ZLIB) +#ifdef HAVE_ZLIB z_stream stream = {}; @@ -102,38 +98,6 @@ ByteVector zlib::decompress(const ByteVector &data) return outData; -#elif defined(HAVE_BOOST_ZLIB) - - using namespace boost::iostreams; - - struct : public sink - { - ByteVector data; - - typedef char char_type; - typedef sink_tag category; - - std::streamsize write(char const* s, std::streamsize n) - { - const unsigned int originalSize = data.size(); - - data.resize(static_cast(originalSize + n)); - ::memcpy(data.data() + originalSize, s, static_cast(n)); - - return n; - } - } sink; - - try { - zlib_decompressor().write(sink, data.data(), data.size()); - } - catch(const zlib_error &) { - debug("zlib::decompress() - Error reading compressed stream."); - return ByteVector(); - } - - return sink.data; - #else return ByteVector(); diff --git a/3rdparty/taglib/toolkit/unicode.cpp b/3rdparty/taglib/toolkit/unicode.cpp deleted file mode 100644 index 1b26977e5..000000000 --- a/3rdparty/taglib/toolkit/unicode.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/******************************************************************************* - * * - * THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB * - * AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. * - * AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. * - * * - *******************************************************************************/ - -/* - * Copyright 2001 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* - * This file has been modified by Scott Wheeler to remove - * the UTF32 conversion functions and to place the appropriate functions - * in their own C++ namespace. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Source code file. - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. - - See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - - -#include "unicode.h" -#include - -#define UNI_SUR_HIGH_START (UTF32)0xD800 -#define UNI_SUR_HIGH_END (UTF32)0xDBFF -#define UNI_SUR_LOW_START (UTF32)0xDC00 -#define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 - -namespace Unicode { - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... six byte sequence.) - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. - * Constants have been gathered. Loops & conditionals have been removed as - * much as possible for efficiency, in favor of drop-through switches. - * (See "Note A" at the bottom of the file for equivalent code.) - * If your compiler supports it, the "isLegalUTF8" call can be turned - * into an inline function. - */ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END && source < sourceEnd) { - UTF32 ch2 = *source; - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else if ((flags == strictConversion) && (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x200000) { bytesToWrite = 4; - } else { bytesToWrite = 2; - ch = UNI_REPLACEMENT_CHAR; - } - // printf("bytes to write = %i\n", bytesToWrite); - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (ch | byteMark) & byteMask; ch >>= 6; - case 3: *--target = (ch | byteMark) & byteMask; ch >>= 6; - case 2: *--target = (ch | byteMark) & byteMask; ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - if (*source > 0xF4) return false; - } - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { - return false; - } - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - if ((flags == strictConversion) && (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (ch & halfMask) + UNI_SUR_LOW_START; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -} - -/* --------------------------------------------------------------------- - - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. - - --------------------------------------------------------------------- */ - - diff --git a/3rdparty/taglib/toolkit/unicode.h b/3rdparty/taglib/toolkit/unicode.h deleted file mode 100644 index d3a869f04..000000000 --- a/3rdparty/taglib/toolkit/unicode.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef TAGLIB_UNICODE_H -#define TAGLIB_UNICODE_H - -/******************************************************************************* - * * - * THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB * - * AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. * - * AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. * - * * - *******************************************************************************/ - -#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header - -/* - * Copyright 2001 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* - * This file has been modified by Scott Wheeler to remove - * the UTF32 conversion functions and to place the appropriate functions - * in their own C++ namespace. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Header file. - - Several functions are included here, forming a complete set of - conversions between the three formats. UTF-7 is not included - here, but is handled in a separate source file. - - Each of these routines takes pointers to input buffers and output - buffers. The input buffers are const. - - Each routine converts the text between *sourceStart and sourceEnd, - putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. - *(sourceEnd - 1) is the last item. - - The return result indicates whether the conversion was successful, - and if not, whether the problem was in the source or target buffers. - (Only the first encountered problem is indicated.) - - After the conversion, *sourceStart and *targetStart are both - updated to point to the end of last text successfully converted in - the respective buffers. - - Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. - - These conversion functions take a ConversionFlags argument. When this - flag is set to strict, both irregular sequences and isolated surrogates - will cause an error. When the flag is set to lenient, both irregular - sequences and isolated surrogates are converted. - - Whether the flag is strict or lenient, all illegal sequences will cause - an error return. This includes sequences such as: , , - or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code - must check for illegal sequences. - - When the flag is set to lenient, characters over 0x10FFFF are converted - to the replacement character; otherwise (when the flag is set to strict) - they constitute an error. - - Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. - - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------- - The following 4 definitions are compiler-specific. - The C standard does not guarantee that wchar_t has at least - 16 bits, so wchar_t is no less portable than unsigned short! - All should be unsigned values to avoid sign extension during - bit mask & shift operations. ------------------------------------------------------------------------- */ - -/* Some fundamental constants */ -#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD -#define UNI_MAX_BMP (UTF32)0x0000FFFF -#define UNI_MAX_UTF16 (UTF32)0x0010FFFF -#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF - -namespace Unicode { - -typedef unsigned long UTF32; /* at least 32 bits */ -typedef wchar_t UTF16; /* TagLib assumes that wchar_t is sufficient for UTF-16. */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ - -typedef enum { - conversionOK = 0, /* conversion successful */ - sourceExhausted = 1, /* partial character in source, but hit end */ - targetExhausted = 2, /* insuff. room in target for conversion */ - sourceIllegal = 3 /* source sequence is illegal/malformed */ -} ConversionResult; - -typedef enum { - strictConversion = 0, - lenientConversion -} ConversionFlags; - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); - -} // namespace Unicode - -/* --------------------------------------------------------------------- */ - -#endif -#endif diff --git a/3rdparty/taglib/trueaudio/trueaudiofile.cpp b/3rdparty/taglib/trueaudio/trueaudiofile.cpp index fc123ba34..e4de436ed 100644 --- a/3rdparty/taglib/trueaudio/trueaudiofile.cpp +++ b/3rdparty/taglib/trueaudio/trueaudiofile.cpp @@ -73,6 +73,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool TrueAudio::File::isSupported(IOStream *stream) +{ + // A TrueAudio file has to start with "TTA". An ID3v2 tag may precede. + + const ByteVector id = Utils::readHeader(stream, 3, true); + return (id == "TTA"); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/trueaudio/trueaudiofile.h b/3rdparty/taglib/trueaudio/trueaudiofile.h index 4bcb722af..3737ac63f 100644 --- a/3rdparty/taglib/trueaudio/trueaudiofile.h +++ b/3rdparty/taglib/trueaudio/trueaudiofile.h @@ -235,6 +235,15 @@ namespace TagLib { */ bool hasID3v2Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as a TrueAudio + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/wavpack/wavpackfile.cpp b/3rdparty/taglib/wavpack/wavpackfile.cpp index ef92f4bdf..01bdba36c 100644 --- a/3rdparty/taglib/wavpack/wavpackfile.cpp +++ b/3rdparty/taglib/wavpack/wavpackfile.cpp @@ -71,6 +71,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool WavPack::File::isSupported(IOStream *stream) +{ + // A WavPack file has to start with "wvpk". + + const ByteVector id = Utils::readHeader(stream, 4, false); + return (id == "wvpk"); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/3rdparty/taglib/wavpack/wavpackfile.h b/3rdparty/taglib/wavpack/wavpackfile.h index 7e0bd27a9..ccc4ef6e8 100644 --- a/3rdparty/taglib/wavpack/wavpackfile.h +++ b/3rdparty/taglib/wavpack/wavpackfile.h @@ -200,6 +200,14 @@ namespace TagLib { */ bool hasAPETag() const; + /*! + * Check if the given \a stream can be opened as a WavPack file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/3rdparty/taglib/xm/xmfile.cpp b/3rdparty/taglib/xm/xmfile.cpp index 9192e9bf2..216dfd8cd 100644 --- a/3rdparty/taglib/xm/xmfile.cpp +++ b/3rdparty/taglib/xm/xmfile.cpp @@ -586,9 +586,9 @@ void XM::File::read(bool) unsigned int count = 4 + instrument.read(*this, instrumentHeaderSize - 4U); READ_ASSERT(count == std::min(instrumentHeaderSize, (unsigned long)instrument.size() + 4)); - unsigned long sampleHeaderSize = 0; long offset = 0; if(sampleCount > 0) { + unsigned long sampleHeaderSize = 0; sumSampleCount += sampleCount; // wouldn't know which header size to assume otherwise: READ_ASSERT(instrumentHeaderSize >= count + 4 && readU32L(sampleHeaderSize)); diff --git a/3rdparty/taglib/xm/xmproperties.cpp b/3rdparty/taglib/xm/xmproperties.cpp index 39a9fa0a0..93d849868 100644 --- a/3rdparty/taglib/xm/xmproperties.cpp +++ b/3rdparty/taglib/xm/xmproperties.cpp @@ -60,7 +60,7 @@ public: XM::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), - d(new PropertiesPrivate) + d(new PropertiesPrivate()) { } diff --git a/3rdparty/utf8-cpp/CMakeLists.txt b/3rdparty/utf8-cpp/CMakeLists.txt new file mode 100644 index 000000000..e438780c8 --- /dev/null +++ b/3rdparty/utf8-cpp/CMakeLists.txt @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 2.8.11) +set(CMAKE_CXX_STANDARD 11) diff --git a/3rdparty/utf8-cpp/checked.h b/3rdparty/utf8-cpp/checked.h new file mode 100644 index 000000000..2aef5838d --- /dev/null +++ b/3rdparty/utf8-cpp/checked.h @@ -0,0 +1,327 @@ +// Copyright 2006-2016 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public ::std::exception { + }; + + // Exceptions that may be thrown from the library functions. + 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"; } + 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"; } + 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"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!utf8::internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = utf8::internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + out = utf8::append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + out = utf8::append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (start != end && utf8::internal::is_trail(*start)) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); + return utf8::replace_invalid(start, end, out, replacement_marker); + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return utf8::next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + // can't do much if it == start + if (it == start) + throw not_enough_room(); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (utf8::internal::is_trail(*(--it))) + if (it == start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + return utf8::peek_next(it, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (utf8::internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return utf8::next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + utf8::next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + if (utf8::internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (utf8::internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = utf8::append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = utf8::next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = utf8::next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& rangestart, + const octet_iterator& rangeend) : + it(octet_it), range_start(rangestart), range_end(rangeend) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + utf8::next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + utf8::next(it, range_end); + return temp; + } + iterator& operator -- () + { + utf8::prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/3rdparty/utf8-cpp/core.h b/3rdparty/utf8-cpp/core.h new file mode 100644 index 000000000..ae0f367db --- /dev/null +++ b/3rdparty/utf8-cpp/core.h @@ -0,0 +1,332 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((utf8::internal::mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = utf8::internal::mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// Helper for get_sequence_x + template + utf_error increase_safely(octet_iterator& it, octet_iterator end) + { + if (++it == end) + return NOT_ENOUGH_ROOM; + + if (!utf8::internal::is_trail(*it)) + return INCOMPLETE_SEQUENCE; + + return UTF8_OK; + } + + #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} + + /// get_sequence_x functions decode utf-8 sequences of the length x + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + return UTF8_OK; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); + + return UTF8_OK; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + const octet_difference_type length = utf8::internal::sequence_length(it); + + // Get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 0: + return INVALID_LEAD; + case 1: + err = utf8::internal::get_sequence_1(it, end, cp); + break; + case 2: + err = utf8::internal::get_sequence_2(it, end, cp); + break; + case 3: + err = utf8::internal::get_sequence_3(it, end, cp); + break; + case 4: + err = utf8::internal::get_sequence_4(it, end, cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (utf8::internal::is_code_point_valid(cp)) { + if (!utf8::internal::is_overlong_sequence(cp, length)){ + // Passed! Return here. + code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + uint32_t ignored; + return utf8::internal::validate_next(it, end, ignored); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (utf8::find_invalid(start, end) == end); + } + + template + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && + ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && + ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template + inline bool is_bom (octet_iterator it) + { + return ( + (utf8::internal::mask8(*it++)) == bom[0] && + (utf8::internal::mask8(*it++)) == bom[1] && + (utf8::internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/CMakeLists.txt b/CMakeLists.txt index bdbaab9a4..ec71934b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,11 +96,12 @@ find_path(SPARSEHASH_INCLUDE_DIRS google/sparsetable) option(USE_BUILTIN_TAGLIB "If the system's version of Taglib is too old, compile our builtin version instead" ON) if (USE_BUILTIN_TAGLIB AND TAGLIB_VERSION VERSION_LESS 1.8) message(STATUS "Using builtin taglib because your system's version is too old") - set(TAGLIB_VERSION 1.11.0) + set(TAGLIB_VERSION 1.11.1) 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) set(TAGLIB_HAS_OPUS ON) + add_subdirectory(3rdparty/utf8-cpp) add_subdirectory(3rdparty/taglib) else() set(CMAKE_REQUIRED_INCLUDES "${TAGLIB_INCLUDE_DIRS}")