From 0195eef865c8ef34a3c2f5db218933515f6d2145 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Tue, 16 Apr 2013 14:35:47 +0900 Subject: [PATCH 01/33] Small refactoring of tbytevector.cpp --- taglib/toolkit/tbytevector.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 31e11d65..5fc6ded5 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -208,22 +208,21 @@ T toNumber(const ByteVector &v, bool mostSignificantByteFirst) return 0; } - const size_t size = sizeof(T); - - if(v.size() >= size) - { + if(v.size() >= sizeof(T)) { if(isLittleEndianSystem == mostSignificantByteFirst) return byteSwap(*reinterpret_cast(v.data())); else return *reinterpret_cast(v.data()); } + else { + T sum = 0; + for(size_t i = 0; i < v.size(); i++) { + const size_t shift = (mostSignificantByteFirst ? v.size() - 1 - i : i) * 8; + sum |= static_cast(static_cast(v[i]) << shift); + } - const uint last = std::min(v.size() - 1, size); - T sum = 0; - for(uint i = 0; i <= last; i++) - sum |= (T) uchar(v[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); - - return sum; + return sum; + } } template From 8c427c7de94f200cb8497ddd2c0006d4067c84de Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Tue, 16 Apr 2013 19:57:04 +0900 Subject: [PATCH 02/33] Small refactoring of tbytevector.cpp --- taglib/toolkit/tbytevector.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 5fc6ded5..ca65cfaa 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -248,6 +248,12 @@ public: { } + // A char* can be an iterator. + DataPrivate(const char *begin, const char *end) + : data(begin, end) + { + } + DataPrivate(uint len, char c) : data(len, c) { @@ -294,12 +300,10 @@ public: ByteVectorPrivate(const char *s, uint l) : RefCounter() - , data(new DataPrivate()) + , data(new DataPrivate(s, s + l)) , offset(0) , length(l) { - data->data.resize(length); - memcpy(DATA(this), s, l); } void detach() From c13921b7c79992d14ada4b0abe25efb386be693e Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Tue, 16 Apr 2013 21:47:12 +0900 Subject: [PATCH 03/33] Small refactoring of tstring.cpp --- taglib/toolkit/tstring.cpp | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 5fe6f45e..219d3daf 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -24,7 +24,6 @@ ***************************************************************************/ // This class assumes that std::basic_string has a contiguous and null-terminated buffer. -// #include "tstring.h" #include "tdebug.h" @@ -60,8 +59,22 @@ namespace TagLib { class String::StringPrivate : public RefCounter { public: - StringPrivate(const wstring &s) : RefCounter(), data(s) {} - StringPrivate() : RefCounter() {} + StringPrivate() + : RefCounter() + { + } + + StringPrivate(const wstring &s) + : RefCounter() + , data(s) + { + } + + StringPrivate(uint n, wchar_t c) + : RefCounter() + , data(static_cast(n), c) + { + } /*! * Stores string in UTF-16. The byte order depends on the CPU endian. @@ -144,14 +157,10 @@ String::String(wchar_t c, Type t) } String::String(char c, Type t) - : d(new StringPrivate()) + : d(new StringPrivate(1, static_cast(c))) { - if(t == Latin1 || t == UTF8) { - d->data.resize(1); - d->data[0] = static_cast(c); - } - else { - debug("String::String() -- A char should not contain UTF16."); + if(t != Latin1 && t != UTF8) { + debug("String::String() -- A char should not contain UTF16."); } } @@ -640,6 +649,7 @@ String &String::operator=(const wchar_t *s) { if(d->deref()) delete d; + d = new StringPrivate(s); return *this; } @@ -648,8 +658,8 @@ String &String::operator=(char c) { if(d->deref()) delete d; - d = new StringPrivate; - d->data += uchar(c); + + d = new StringPrivate(1, static_cast(c)); return *this; } @@ -657,8 +667,8 @@ String &String::operator=(wchar_t c) { if(d->deref()) delete d; - d = new StringPrivate; - d->data += c; + + d = new StringPrivate(1, static_cast(c)); return *this; } From b14dc1572ddd646d6bab1f4f118561118c373cb3 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 10:10:25 +0900 Subject: [PATCH 04/33] Replace RefCounter with a smart pointer --- taglib/CMakeLists.txt | 5 + taglib/asf/asfattribute.cpp | 24 ++-- taglib/asf/asfattribute.h | 2 +- taglib/asf/asfpicture.cpp | 14 +- taglib/asf/asfpicture.h | 8 +- taglib/fileref.cpp | 70 +++++----- taglib/fileref.h | 5 +- taglib/mp4/mp4coverart.cpp | 14 +- taglib/mp4/mp4coverart.h | 2 +- taglib/mp4/mp4item.cpp | 32 ++--- taglib/mp4/mp4item.h | 2 +- taglib/mpeg/mpegheader.cpp | 17 +-- taglib/mpeg/mpegheader.h | 3 +- taglib/toolkit/taglib.h | 66 +-------- taglib/toolkit/tbytevector.cpp | 65 +++------ taglib/toolkit/tbytevector.h | 6 +- taglib/toolkit/tiostream.h | 5 + taglib/toolkit/tlist.h | 4 +- taglib/toolkit/tlist.tcc | 52 +++---- taglib/toolkit/tmap.h | 5 +- taglib/toolkit/tmap.tcc | 47 ++++--- taglib/toolkit/trefcountptr.h | 240 +++++++++++++++++++++++++++++++++ taglib/toolkit/tstring.cpp | 59 ++------ taglib/toolkit/tstring.h | 6 +- 24 files changed, 427 insertions(+), 326 deletions(-) create mode 100644 taglib/toolkit/trefcountptr.h diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index a940caf5..dab3430e 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -51,6 +51,7 @@ set(tag_HDRS toolkit/tmap.tcc toolkit/tpropertymap.h toolkit/tbyteswap.h + toolkit/trefcountptr.h mpeg/mpegfile.h mpeg/mpegproperties.h mpeg/mpegheader.h @@ -311,6 +312,10 @@ if(ZLIB_FOUND) target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() +if(WIN32 AND NOT TAGLIB_STATIC) + target_link_libraries(tag shlwapi.lib) +endif() + set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} diff --git a/taglib/asf/asfattribute.cpp b/taglib/asf/asfattribute.cpp index 2cfada7b..4ba2689b 100644 --- a/taglib/asf/asfattribute.cpp +++ b/taglib/asf/asfattribute.cpp @@ -34,7 +34,7 @@ using namespace TagLib; -class ASF::Attribute::AttributePrivate : public RefCounter +class ASF::Attribute::AttributePrivate { public: AttributePrivate() @@ -60,77 +60,71 @@ public: //////////////////////////////////////////////////////////////////////////////// ASF::Attribute::Attribute() + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = UnicodeType; } ASF::Attribute::Attribute(const ASF::Attribute &other) : d(other.d) { - d->ref(); } ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) { - if(d->deref()) - delete d; d = other.d; - d->ref(); return *this; } ASF::Attribute::~Attribute() { - if(d->deref()) - delete d; } ASF::Attribute::Attribute(const String &value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = UnicodeType; d->stringValue = value; } ASF::Attribute::Attribute(const ByteVector &value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = BytesType; d->byteVectorValue = value; } ASF::Attribute::Attribute(const ASF::Picture &value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = BytesType; d->pictureValue = value; } ASF::Attribute::Attribute(unsigned int value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = DWordType; d->intValue = value; } ASF::Attribute::Attribute(unsigned long long value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = QWordType; d->longLongValue = value; } ASF::Attribute::Attribute(unsigned short value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = WordType; d->shortValue = value; } ASF::Attribute::Attribute(bool value) + : d(new AttributePrivate()) { - d = new AttributePrivate; d->type = BoolType; d->boolValue = value; } diff --git a/taglib/asf/asfattribute.h b/taglib/asf/asfattribute.h index 54eb0c7d..ca26aec3 100644 --- a/taglib/asf/asfattribute.h +++ b/taglib/asf/asfattribute.h @@ -194,7 +194,7 @@ namespace TagLib ByteVector render(const String &name, int kind = 0) const; class AttributePrivate; - AttributePrivate *d; + RefCountPtr d; }; } diff --git a/taglib/asf/asfpicture.cpp b/taglib/asf/asfpicture.cpp index c36ffa3a..82a38b6b 100644 --- a/taglib/asf/asfpicture.cpp +++ b/taglib/asf/asfpicture.cpp @@ -35,7 +35,7 @@ using namespace TagLib; -class ASF::Picture::PicturePrivate : public RefCounter +class ASF::Picture::PicturePrivate { public: bool valid; @@ -50,21 +50,18 @@ public: //////////////////////////////////////////////////////////////////////////////// ASF::Picture::Picture() + : d(new PicturePrivate()) { - d = new PicturePrivate(); d->valid = true; } ASF::Picture::Picture(const Picture& other) : d(other.d) { - d->ref(); } ASF::Picture::~Picture() { - if(d->deref()) - delete d; } bool ASF::Picture::isValid() const @@ -121,12 +118,7 @@ int ASF::Picture::dataSize() const ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other) { - if(other.d != d) { - if(d->deref()) - delete d; - d = other.d; - d->ref(); - } + d = other.d; return *this; } diff --git a/taglib/asf/asfpicture.h b/taglib/asf/asfpicture.h index aa0a060c..aa838974 100644 --- a/taglib/asf/asfpicture.h +++ b/taglib/asf/asfpicture.h @@ -207,10 +207,10 @@ namespace TagLib static Picture fromInvalid(); friend class Attribute; #endif - private: - class PicturePrivate; - PicturePrivate *d; - }; + private: + class PicturePrivate; + RefCountPtr d; + }; } } diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 859f3155..8e747fa8 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -31,6 +31,10 @@ #include #endif +#ifdef _WIN32 +# include +#endif + #include #include #include @@ -57,15 +61,12 @@ using namespace TagLib; -class FileRef::FileRefPrivate : public RefCounter +class FileRef::FileRefPrivate { public: - FileRefPrivate(File *f) : RefCounter(), file(f) {} - ~FileRefPrivate() { - delete file; - } + FileRefPrivate(File *f) : file(f) {} - File *file; + RefCountPtr file; static List fileTypeResolvers; }; @@ -76,30 +77,28 @@ List FileRef::FileRefPrivate::fileTypeResolve //////////////////////////////////////////////////////////////////////////////// FileRef::FileRef() + : d(new FileRefPrivate(0)) { - d = new FileRefPrivate(0); } -FileRef::FileRef(FileName fileName, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) +FileRef::FileRef( + FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) + : d(new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle))) { - d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle)); } FileRef::FileRef(File *file) + : d(new FileRefPrivate(file)) { - d = new FileRefPrivate(file); } -FileRef::FileRef(const FileRef &ref) : d(ref.d) +FileRef::FileRef(const FileRef &ref) + : d(ref.d) { - d->ref(); } FileRef::~FileRef() { - if(d->deref()) - delete d; } Tag *FileRef::tag() const @@ -122,7 +121,7 @@ AudioProperties *FileRef::audioProperties() const File *FileRef::file() const { - return d->file; + return d->file.get(); } bool FileRef::save() @@ -182,15 +181,7 @@ bool FileRef::isNull() const FileRef &FileRef::operator=(const FileRef &ref) { - if(&ref == this) - return *this; - - if(d->deref()) - delete d; - d = ref.d; - d->ref(); - return *this; } @@ -218,21 +209,36 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, // Ok, this is really dumb for now, but it works for testing. - String s; + String ext; #ifdef _WIN32 - s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName); + // Avoids direct conversion from FileName to String + // because String can't accept non-Latin-1 string in char array. + + if(!fileName.wstr().empty()) { + const wchar_t *pext = PathFindExtensionW(fileName.wstr().c_str()); + if(*pext == L'.') + ext = String(pext + 1).upper(); + } + else { + const char *pext = PathFindExtensionA(fileName.str().c_str()); + if(*pext == '.') + ext = String(pext + 1).upper(); + } #else - s = fileName; + { + String s = fileName; + const int pos = s.rfind("."); + if(pos != -1) + ext = s.substr(pos + 1).upper(); + } #endif // If this list is updated, the method defaultFileExtensions() should also be // updated. However at some point that list should be created at the same time // that a default file type resolver is created. - int pos = s.rfind("."); - if(pos != -1) { - String ext = s.substr(pos + 1).upper(); + if(!ext.isEmpty()) { if(ext == "MP3") return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OGG") @@ -280,3 +286,7 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, return 0; } + +FileRef::FileTypeResolver::~FileTypeResolver() +{ +} diff --git a/taglib/fileref.h b/taglib/fileref.h index 0f0c21a4..42cec8b4 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -91,7 +91,6 @@ namespace TagLib { class TAGLIB_EXPORT FileTypeResolver { - TAGLIB_IGNORE_MISSING_DESTRUCTOR public: /*! * This method must be overridden to provide an additional file type @@ -106,6 +105,8 @@ namespace TagLib { bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0; + + virtual ~FileTypeResolver(); }; /*! @@ -255,7 +256,7 @@ namespace TagLib { private: class FileRefPrivate; - FileRefPrivate *d; + RefCountPtr d; }; } // namespace TagLib diff --git a/taglib/mp4/mp4coverart.cpp b/taglib/mp4/mp4coverart.cpp index 928e3c4a..5b6e6e23 100644 --- a/taglib/mp4/mp4coverart.cpp +++ b/taglib/mp4/mp4coverart.cpp @@ -33,43 +33,35 @@ using namespace TagLib; -class MP4::CoverArt::CoverArtPrivate : public RefCounter +class MP4::CoverArt::CoverArtPrivate { public: - CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {} + CoverArtPrivate() : format(MP4::CoverArt::JPEG) {} Format format; ByteVector data; }; MP4::CoverArt::CoverArt(Format format, const ByteVector &data) + : d(new CoverArtPrivate()) { - d = new CoverArtPrivate; d->format = format; d->data = data; } MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d) { - d->ref(); } MP4::CoverArt & MP4::CoverArt::operator=(const CoverArt &item) { - if(d->deref()) { - delete d; - } d = item.d; - d->ref(); return *this; } MP4::CoverArt::~CoverArt() { - if(d->deref()) { - delete d; - } } MP4::CoverArt::Format diff --git a/taglib/mp4/mp4coverart.h b/taglib/mp4/mp4coverart.h index 64115b45..b6b44c49 100644 --- a/taglib/mp4/mp4coverart.h +++ b/taglib/mp4/mp4coverart.h @@ -63,7 +63,7 @@ namespace TagLib { private: class CoverArtPrivate; - CoverArtPrivate *d; + RefCountPtr d; }; typedef List CoverArtList; diff --git a/taglib/mp4/mp4item.cpp b/taglib/mp4/mp4item.cpp index af2cc65c..6a303652 100644 --- a/taglib/mp4/mp4item.cpp +++ b/taglib/mp4/mp4item.cpp @@ -33,10 +33,10 @@ using namespace TagLib; -class MP4::Item::ItemPrivate : public RefCounter +class MP4::Item::ItemPrivate { public: - ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {} + ItemPrivate() : valid(true), atomDataType(TypeUndefined) {} bool valid; AtomDataType atomDataType; @@ -54,86 +54,78 @@ public: }; MP4::Item::Item() + : d(new ItemPrivate()) { - d = new ItemPrivate; d->valid = false; } MP4::Item::Item(const Item &item) : d(item.d) { - d->ref(); } MP4::Item & MP4::Item::operator=(const Item &item) { - if(d->deref()) { - delete d; - } d = item.d; - d->ref(); return *this; } MP4::Item::~Item() { - if(d->deref()) { - delete d; - } } MP4::Item::Item(bool value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_bool = value; } MP4::Item::Item(int value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_int = value; } MP4::Item::Item(uchar value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_byte = value; } MP4::Item::Item(uint value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_uint = value; } MP4::Item::Item(long long value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_longlong = value; } MP4::Item::Item(int value1, int value2) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_intPair.first = value1; d->m_intPair.second = value2; } MP4::Item::Item(const ByteVectorList &value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_byteVectorList = value; } MP4::Item::Item(const StringList &value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_stringList = value; } MP4::Item::Item(const MP4::CoverArtList &value) + : d(new ItemPrivate()) { - d = new ItemPrivate; d->m_coverArtList = value; } diff --git a/taglib/mp4/mp4item.h b/taglib/mp4/mp4item.h index be7aa1a1..3b4e23cd 100644 --- a/taglib/mp4/mp4item.h +++ b/taglib/mp4/mp4item.h @@ -73,7 +73,7 @@ namespace TagLib { private: class ItemPrivate; - ItemPrivate *d; + RefCountPtr d; }; } diff --git a/taglib/mpeg/mpegheader.cpp b/taglib/mpeg/mpegheader.cpp index c715dbc1..bc98f4c9 100644 --- a/taglib/mpeg/mpegheader.cpp +++ b/taglib/mpeg/mpegheader.cpp @@ -33,7 +33,7 @@ using namespace TagLib; -class MPEG::Header::HeaderPrivate : public RefCounter +class MPEG::Header::HeaderPrivate { public: HeaderPrivate() : @@ -68,20 +68,18 @@ public: //////////////////////////////////////////////////////////////////////////////// MPEG::Header::Header(const ByteVector &data) + : d(new HeaderPrivate()) { - d = new HeaderPrivate; parse(data); } -MPEG::Header::Header(const Header &h) : d(h.d) +MPEG::Header::Header(const Header &h) + : d(h.d) { - d->ref(); } MPEG::Header::~Header() { - if (d->deref()) - delete d; } bool MPEG::Header::isValid() const @@ -146,14 +144,7 @@ int MPEG::Header::samplesPerFrame() const MPEG::Header &MPEG::Header::operator=(const Header &h) { - if(&h == this) - return *this; - - if(d->deref()) - delete d; - d = h.d; - d->ref(); return *this; } diff --git a/taglib/mpeg/mpegheader.h b/taglib/mpeg/mpegheader.h index 020ebd06..7a352ed7 100644 --- a/taglib/mpeg/mpegheader.h +++ b/taglib/mpeg/mpegheader.h @@ -27,6 +27,7 @@ #define TAGLIB_MPEGHEADER_H #include "taglib_export.h" +#include "trefcountptr.h" namespace TagLib { @@ -158,7 +159,7 @@ namespace TagLib { void parse(const ByteVector &data); class HeaderPrivate; - HeaderPrivate *d; + RefCountPtr d; }; } } diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index dd4ee69d..03d16724 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -45,23 +45,11 @@ #include #include -#ifdef __APPLE__ -# include -# define TAGLIB_ATOMIC_MAC -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if !defined(NOMINMAX) -# define NOMINMAX -# endif -# include -# define TAGLIB_ATOMIC_WIN -#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ - && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ - defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ - && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -#elif defined(__ia64) && defined(__INTEL_COMPILER) -# include -# define TAGLIB_ATOMIC_GCC +#ifdef _WIN32 +# if !defined(NOMINMAX) +# define NOMINMAX +# endif +# include #endif // Check the widths of integral types. @@ -116,50 +104,6 @@ namespace TagLib { * so I'm providing something here that should be constant. */ typedef std::basic_string wstring; - -#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. - /*! - * \internal - * This is just used as a base class for shared classes in TagLib. - * - * \warning This is not part of the TagLib public API! - */ - - class RefCounter - { - public: - RefCounter() : refCount(1) {} - -#ifdef TAGLIB_ATOMIC_MAC - void ref() { OSAtomicIncrement32Barrier(const_cast(&refCount)); } - bool deref() { return ! OSAtomicDecrement32Barrier(const_cast(&refCount)); } - int32_t count() { return refCount; } - private: - volatile int32_t refCount; -#elif defined(TAGLIB_ATOMIC_WIN) - void ref() { InterlockedIncrement(&refCount); } - bool deref() { return ! InterlockedDecrement(&refCount); } - long count() { return refCount; } - private: - volatile long refCount; -#elif defined(TAGLIB_ATOMIC_GCC) - void ref() { __sync_add_and_fetch(&refCount, 1); } - bool deref() { return ! __sync_sub_and_fetch(&refCount, 1); } - int count() { return refCount; } - private: - volatile int refCount; -#else - void ref() { refCount++; } - bool deref() { return ! --refCount; } - int count() { return refCount; } - private: - uint refCount; -#endif - - }; - -#endif // DO_NOT_DOCUMENT - } /*! diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index ca65cfaa..aa76d6bf 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -236,7 +236,7 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst) return ByteVector(reinterpret_cast(&value), size); } -class DataPrivate : public RefCounter +class DataPrivate { public: DataPrivate() @@ -262,45 +262,39 @@ public: std::vector data; }; -class ByteVector::ByteVectorPrivate : public RefCounter +class ByteVector::ByteVectorPrivate { public: ByteVectorPrivate() - : RefCounter() - , data(new DataPrivate()) + : data(new DataPrivate()) , offset(0) , length(0) { } - ByteVectorPrivate(ByteVectorPrivate *d, uint o, uint l) - : RefCounter() - , data(d->data) + ByteVectorPrivate(RefCountPtr d, uint o, uint l) + : data(d->data) , offset(d->offset + o) , length(l) { - data->ref(); } ByteVectorPrivate(const std::vector &v, uint o, uint l) - : RefCounter() - , data(new DataPrivate(v, o, l)) + : data(new DataPrivate(v, o, l)) , offset(0) , length(l) { } ByteVectorPrivate(uint l, char c) - : RefCounter() - , data(new DataPrivate(l, c)) + : data(new DataPrivate(l, c)) , offset(0) , length(l) { } ByteVectorPrivate(const char *s, uint l) - : RefCounter() - , data(new DataPrivate(s, s + l)) + : data(new DataPrivate(s, s + l)) , offset(0) , length(l) { @@ -308,34 +302,25 @@ public: void detach() { - if(data->count() > 1) { - data->deref(); - data = new DataPrivate(data->data, offset, length); + if(!data.unique()) { + data.reset(new DataPrivate(data->data, offset, length)); offset = 0; } } ~ByteVectorPrivate() { - if(data->deref()) - delete data; } ByteVectorPrivate &operator=(const ByteVectorPrivate &x) { if(&x != this) - { - if(data->deref()) - delete data; - data = x.data; - data->ref(); - } return *this; } - DataPrivate *data; + RefCountPtr data; uint offset; uint length; }; @@ -386,13 +371,11 @@ ByteVector::ByteVector(uint size, char value) ByteVector::ByteVector(const ByteVector &v) : d(v.d) { - d->ref(); } ByteVector::ByteVector(const ByteVector &v, uint offset, uint length) : d(new ByteVectorPrivate(v.d, offset, length)) { - d->ref(); } ByteVector::ByteVector(char c) @@ -412,8 +395,6 @@ ByteVector::ByteVector(const char *data) ByteVector::~ByteVector() { - if(d->deref()) - delete d; } ByteVector &ByteVector::setData(const char *s, uint length) @@ -563,10 +544,7 @@ ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &wit } // replace private data: - if(d->deref()) - delete d; - - d = newData; + d.reset(newData); return *this; } @@ -765,14 +743,7 @@ ByteVector ByteVector::operator+(const ByteVector &v) const ByteVector &ByteVector::operator=(const ByteVector &v) { - if(&v == this) - return *this; - - if(d->deref()) - delete d; - d = v.d; - d->ref(); return *this; } @@ -808,16 +779,10 @@ ByteVector ByteVector::toHex() const void ByteVector::detach() { - if(d->data->count() > 1) { - d->data->deref(); - d->data = new DataPrivate(d->data->data, d->offset, d->length); - d->offset = 0; - } + d->detach(); - if(d->count() > 1) { - d->deref(); - d = new ByteVectorPrivate(d->data->data, d->offset, d->length); - } + if(!d.unique()) + d.reset(new ByteVectorPrivate(d->data->data, d->offset, d->length)); } } diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index ca810130..cf7f66d5 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -26,9 +26,9 @@ #ifndef TAGLIB_BYTEVECTOR_H #define TAGLIB_BYTEVECTOR_H -#include "taglib.h" #include "taglib_export.h" - +#include "taglib.h" +#include "trefcountptr.h" #include #include @@ -446,7 +446,7 @@ namespace TagLib { private: class ByteVectorPrivate; - ByteVectorPrivate *d; + RefCountPtr d; }; } diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index 3e7de22a..ce1a0d0d 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -38,8 +38,13 @@ namespace TagLib { public: FileName(const wchar_t *name) : m_wname(name) {} FileName(const char *name) : m_name(name) {} + operator const wchar_t *() const { return m_wname.c_str(); } operator const char *() const { return m_name.c_str(); } + + const std::wstring &wstr() const { return m_wname; } + const std::string &str() const { return m_name; } + private: std::string m_name; std::wstring m_wname; diff --git a/taglib/toolkit/tlist.h b/taglib/toolkit/tlist.h index 0099dad5..535b374f 100644 --- a/taglib/toolkit/tlist.h +++ b/taglib/toolkit/tlist.h @@ -27,7 +27,7 @@ #define TAGLIB_LIST_H #include "taglib.h" - +#include "trefcountptr.h" #include namespace TagLib { @@ -243,7 +243,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class ListPrivate; - ListPrivate *d; + RefCountPtr > d; #endif }; diff --git a/taglib/toolkit/tlist.tcc b/taglib/toolkit/tlist.tcc index 37817f05..17d68a5a 100644 --- a/taglib/toolkit/tlist.tcc +++ b/taglib/toolkit/tlist.tcc @@ -38,7 +38,7 @@ namespace TagLib { // A base for the generic and specialized private class types. New // non-templatized members should be added here. -class ListPrivateBase : public RefCounter +class ListPrivateBase { public: ListPrivateBase() : autoDelete(false) {} @@ -53,8 +53,9 @@ template class List::ListPrivate : public ListPrivateBase public: ListPrivate() : ListPrivateBase() {} ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} + void clear() { - list.clear(); + std::list().swap(list); } std::list list; }; @@ -68,18 +69,27 @@ template class List::ListPrivate : public ListPrivateBase public: ListPrivate() : ListPrivateBase() {} ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} + ~ListPrivate() { - clear(); + deletePointers(); } + void clear() { - if(autoDelete) { - typename std::list::const_iterator it = list.begin(); - for(; it != list.end(); ++it) - delete *it; - } - list.clear(); + deletePointers(); + std::list().swap(list); } + std::list list; + +private: + void deletePointers() { + if(!autoDelete) + return; + + typename std::list::const_iterator it = list.begin(); + for(; it != list.end(); ++it) + delete *it; + } }; //////////////////////////////////////////////////////////////////////////////// @@ -88,21 +98,19 @@ public: template List::List() + : d(new ListPrivate()) { - d = new ListPrivate; } template -List::List(const List &l) : d(l.d) +List::List(const List &l) + : d(l.d) { - d->ref(); } template List::~List() { - if(d->deref()) - delete d; } template @@ -179,7 +187,7 @@ template List &List::prepend(const List &l) { detach(); - d->list.insert(d->list.begin(), l.begin(), l.end()); + d->list.insert(d->list.begin(), l.d->list.begin(), l.d->list.end()); return *this; } @@ -192,7 +200,7 @@ List &List::clear() } template -TagLib::uint List::size() const +uint List::size() const { return d->list.size(); } @@ -284,13 +292,7 @@ const T &List::operator[](uint i) const template List &List::operator=(const List &l) { - if(&l == this) - return *this; - - if(d->deref()) - delete d; d = l.d; - d->ref(); return *this; } @@ -313,10 +315,8 @@ bool List::operator!=(const List &l) const template void List::detach() { - if(d->count() > 1) { - d->deref(); - d = new ListPrivate(d->list); - } + if(!d.unique()) + d.reset(new ListPrivate(d->list)); } } // namespace TagLib diff --git a/taglib/toolkit/tmap.h b/taglib/toolkit/tmap.h index a7d99303..b5748e66 100644 --- a/taglib/toolkit/tmap.h +++ b/taglib/toolkit/tmap.h @@ -26,9 +26,10 @@ #ifndef TAGLIB_MAP_H #define TAGLIB_MAP_H +#include "taglib.h" +#include "trefcountptr.h" #include -#include "taglib.h" namespace TagLib { @@ -185,7 +186,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class MapPrivate; - MapPrivate *d; + RefCountPtr > d; #endif }; diff --git a/taglib/toolkit/tmap.tcc b/taglib/toolkit/tmap.tcc index 0f2b9933..783f99cc 100644 --- a/taglib/toolkit/tmap.tcc +++ b/taglib/toolkit/tmap.tcc @@ -31,36 +31,49 @@ namespace TagLib { template template -class Map::MapPrivate : public RefCounter +class Map::MapPrivate { public: - MapPrivate() : RefCounter() {} + MapPrivate() {} + #ifdef WANT_CLASS_INSTANTIATION_OF_MAP - MapPrivate(const std::map& m) : RefCounter(), map(m) {} + + MapPrivate(const std::map &m) : RefCounter(), map(m) {} + + void clear() { + std::map().swap(map); + } + std::map map; + #else - MapPrivate(const std::map& m) : RefCounter(), map(m) {} + + MapPrivate(const std::map& m) : map(m) {} + + void clear() { + std::map().swap(map); + } + std::map map; + #endif }; template Map::Map() + : d(new MapPrivate()) { - d = new MapPrivate; } template -Map::Map(const Map &m) : d(m.d) +Map::Map(const Map &m) + : d(m.d) { - d->ref(); } template Map::~Map() { - if(d->deref()) - delete(d); } template @@ -149,7 +162,7 @@ Map &Map::erase(const Key &key) } template -TagLib::uint Map::size() const +uint Map::size() const { return d->map.size(); } @@ -170,13 +183,7 @@ 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(); return *this; } @@ -187,10 +194,8 @@ Map &Map::operator=(const Map &m) template void Map::detach() { - if(d->count() > 1) { - d->deref(); - d = new MapPrivate(d->map); - } + if(!d.unique()) + d.reset(new MapPrivate(d->map)); } -} // namespace TagLib +} // namespace TagLib \ No newline at end of file diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h new file mode 100644 index 00000000..49e0ee9e --- /dev/null +++ b/taglib/toolkit/trefcountptr.h @@ -0,0 +1,240 @@ +/*************************************************************************** + copyright : (C) 2013 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_REFCOUNTPTR_H +#define TAGLIB_REFCOUNTPTR_H + +#include "tdebug.h" + +#ifdef __APPLE__ +# include +# define TAGLIB_ATOMIC_MAC +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define TAGLIB_ATOMIC_WIN +#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ + && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ + && !defined(__INTEL_COMPILER) +# define TAGLIB_ATOMIC_GCC +#elif defined(__ia64) && defined(__INTEL_COMPILER) +# include +# define TAGLIB_ATOMIC_GCC +#endif + +#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. + +/*! + * \internal + * This is just used as a smart pointer for shared classes in TagLib. + * + * \warning This is not part of the TagLib public API! + */ + +namespace TagLib { + + // RefCountPtr mimics std::shared_ptr. + + template + class RefCountPtr + { + private: + + // Counter base class. Provides a reference counter. + + class counter_base + { + public: + counter_base() + : count(1) + { + } + + virtual ~counter_base() + { + } + + void addref() + { + increment(&count); + } + + void release() + { + if(decrement(&count) == 0) { + dispose(); + delete this; + } + } + + long use_count() const + { + return static_cast(count); + } + + virtual void dispose() = 0; + + private: +# if defined(TAGLIB_ATOMIC_MAC) + typedef volatile int32_t counter_t; + + inline static void increment(counter_t *c) { OSAtomicIncrement32Barrier(c); } + inline static counter_t decrement(counter_t *c) { return OSAtomicDecrement32Barrier(c); } + +# elif defined(TAGLIB_ATOMIC_WIN) + typedef volatile long counter_t; + + inline static void increment(counter_t *c) { InterlockedIncrement(c); } + inline static counter_t decrement(counter_t *c) { return InterlockedDecrement(c); } + +# elif defined(TAGLIB_ATOMIC_GCC) + typedef volatile int counter_t; + + inline static void increment(counter_t *c) { __sync_add_and_fetch(c, 1); } + inline static counter_t decrement(counter_t *c) { return __sync_sub_and_fetch(c, 1); } + +# else + typedef uint counter_t; + + inline static void increment(counter_t *c) { ++(*c) } + inline static counter_t decrement(counter_t *c) { return --(*c); } + +# endif + + counter_t count; + }; + + // Counter impl class. Provides a dynamic deleter. + + template + class counter_impl : public counter_base + { + public: + counter_impl(U *p) + : p(p) + { + } + + virtual void dispose() + { + delete p; + } + + U *get() const + { + return p; + } + + private: + U *p; + }; + + public: + template + explicit RefCountPtr(U *p) + : counter(new counter_impl(p)) + { + } + + RefCountPtr(const RefCountPtr &x) + { + counter = x.counter; + counter->addref(); + } + + ~RefCountPtr() + { + counter->release(); + } + + T *get() const + { + return static_cast*>(counter)->get(); + } + + long use_count() const + { + return counter->use_count(); + } + + bool unique() const + { + return (use_count() == 1); + } + + template + void reset(U *p) + { + if(get() != p) + { + counter->release(); + counter = new counter_impl(p); + } + } + + RefCountPtr &operator=(const RefCountPtr &x) + { + if(get() != x.get()) + { + counter->release(); + + counter = x.counter; + counter->addref(); + } + return *this; + } + + T& operator*() const + { + return *get(); + } + + T* operator->() const + { + return get(); + } + + bool operator==(const RefCountPtr &x) const + { + return (get() == x.get()); + } + + bool operator!=(const RefCountPtr &x) const + { + return !operator==(x); + } + + operator bool() const + { + return (get() != 0); + } + + private: + counter_base *counter; + }; +} + +#endif // DO_NOT_DOCUMENT + +#endif diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 219d3daf..14abae2f 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -30,7 +30,6 @@ #include "tstringlist.h" #include "tbyteswap.h" -#include #include // Determine if the compiler supports codecvt. @@ -56,23 +55,20 @@ namespace { namespace TagLib { -class String::StringPrivate : public RefCounter +class String::StringPrivate { public: StringPrivate() - : RefCounter() { } StringPrivate(const wstring &s) - : RefCounter() - , data(s) + : data(s) { } StringPrivate(uint n, wchar_t c) - : RefCounter() - , data(static_cast(n), c) + : data(static_cast(n), c) { } @@ -99,7 +95,6 @@ String::String() String::String(const String &s) : d(s.d) { - d->ref(); } String::String(const std::string &s, Type t) @@ -182,8 +177,6 @@ String::String(const ByteVector &v, Type t) String::~String() { - if(d->deref()) - delete d; } std::string String::to8Bit(bool unicode) const @@ -616,22 +609,13 @@ String &String::operator+=(char c) String &String::operator=(const String &s) { - if(&s == this) - return *this; - - if(d->deref()) - delete d; d = s.d; - d->ref(); return *this; } String &String::operator=(const std::string &s) { - if(d->deref()) - delete d; - - d = new StringPrivate; + d.reset(new StringPrivate()); copyFromLatin1(s.c_str(), s.length()); return *this; @@ -639,45 +623,33 @@ String &String::operator=(const std::string &s) String &String::operator=(const wstring &s) { - if(d->deref()) - delete d; - d = new StringPrivate(s); + d.reset(new StringPrivate(s)); return *this; } String &String::operator=(const wchar_t *s) { - if(d->deref()) - delete d; + d.reset(new StringPrivate()); + copyFromUTF16(s, ::wcslen(s), WCharByteOrder); - d = new StringPrivate(s); return *this; } String &String::operator=(char c) { - if(d->deref()) - delete d; - - d = new StringPrivate(1, static_cast(c)); + d.reset(new StringPrivate(1, static_cast(c))); return *this; } String &String::operator=(wchar_t c) { - if(d->deref()) - delete d; - - d = new StringPrivate(1, static_cast(c)); + d.reset(new StringPrivate(1, static_cast(c))); return *this; } String &String::operator=(const char *s) { - if(d->deref()) - delete d; - - d = new StringPrivate; + d.reset(new StringPrivate()); copyFromLatin1(s, ::strlen(s)); return *this; @@ -685,10 +657,7 @@ String &String::operator=(const char *s) String &String::operator=(const ByteVector &v) { - if(d->deref()) - delete d; - - d = new StringPrivate; + d.reset(new StringPrivate()); copyFromLatin1(v.data(), v.size()); // If we hit a null in the ByteVector, shrink the string again. @@ -708,10 +677,8 @@ bool String::operator<(const String &s) const void String::detach() { - if(d->count() > 1) { - d->deref(); - d = new StringPrivate(d->data); - } + if(!d.unique()) + d.reset(new StringPrivate(d->data)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index 150d7c37..652c6ca7 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -26,12 +26,8 @@ #ifndef TAGLIB_STRING_H #define TAGLIB_STRING_H -#include "taglib_export.h" -#include "taglib.h" #include "tbytevector.h" - #include -#include /*! * \relates TagLib::String @@ -485,7 +481,7 @@ namespace TagLib { static const Type WCharByteOrder; class StringPrivate; - StringPrivate *d; + RefCountPtr d; }; } From 24736b919a65c0a2ec056c586d87896e42777938 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 11:12:42 +0900 Subject: [PATCH 05/33] Use std::shared_ptr if C++11 is available --- CMakeLists.txt | 5 +++++ taglib/toolkit/trefcountptr.h | 41 ++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f29e463..e56978f5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,11 @@ else() endif() OPTION(ENABLE_STATIC_RUNTIME "Visual Studio, link with runtime statically" OFF) +option(ENABLE_CXX11 "Enable C++11 features" OFF) +if(ENABLE_CXX11) + add_definitions(-DTAGLIB_USE_CXX11) +endif() + option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF) if(VISIBILITY_HIDDEN) add_definitions (-fvisibility=hidden) diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h index 49e0ee9e..eb84e178 100644 --- a/taglib/toolkit/trefcountptr.h +++ b/taglib/toolkit/trefcountptr.h @@ -26,21 +26,26 @@ #ifndef TAGLIB_REFCOUNTPTR_H #define TAGLIB_REFCOUNTPTR_H -#include "tdebug.h" +// TAGLIB_USE_CXX11 determines whether or not to enable C++11 features. -#ifdef __APPLE__ -# include -# define TAGLIB_ATOMIC_MAC -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define TAGLIB_ATOMIC_WIN -#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ +#ifdef TAGLIB_USE_CXX11 +# include + +#else +# ifdef __APPLE__ +# include +# define TAGLIB_ATOMIC_MAC +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define TAGLIB_ATOMIC_WIN +# elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -#elif defined(__ia64) && defined(__INTEL_COMPILER) -# include -# define TAGLIB_ATOMIC_GCC +# define TAGLIB_ATOMIC_GCC +# elif defined(__ia64) && defined(__INTEL_COMPILER) +# include +# define TAGLIB_ATOMIC_GCC +# endif #endif #ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. @@ -52,9 +57,18 @@ * \warning This is not part of the TagLib public API! */ +#ifdef TAGLIB_USE_CXX11 + + // RefCountPtr is just an alias of std::shared_ptr if C++11 is available. +# define RefCountPtr std::shared_ptr + + // Workaround for the fact that some compilers don't support the template aliases. + +#else + namespace TagLib { - // RefCountPtr mimics std::shared_ptr. + // RefCountPtr mimics std::shared_ptr if C++11 is not available. template class RefCountPtr @@ -234,7 +248,8 @@ namespace TagLib { counter_base *counter; }; } +#endif // TAGLIB_USE_CXX11 #endif // DO_NOT_DOCUMENT -#endif +#endif \ No newline at end of file From 94a07fa39af0dae0dea6221ffaa41f073761145b Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 11:33:01 +0900 Subject: [PATCH 06/33] Restore ABI breaking change --- taglib/fileref.cpp | 4 ---- taglib/fileref.h | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 8e747fa8..f3b4ef3c 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -286,7 +286,3 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, return 0; } - -FileRef::FileTypeResolver::~FileTypeResolver() -{ -} diff --git a/taglib/fileref.h b/taglib/fileref.h index 42cec8b4..907727c7 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -91,6 +91,7 @@ namespace TagLib { class TAGLIB_EXPORT FileTypeResolver { + TAGLIB_IGNORE_MISSING_DESTRUCTOR public: /*! * This method must be overridden to provide an additional file type @@ -105,8 +106,6 @@ namespace TagLib { bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0; - - virtual ~FileTypeResolver(); }; /*! From 593eda7d9de1e5d7970b82b93d4114fb42e6a15c Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 12:28:00 +0900 Subject: [PATCH 07/33] Restore ABI changed in pull request #60 --- taglib/riff/rifffile.cpp | 5 +++++ taglib/riff/rifffile.h | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index a38e1c40..20eec5ff 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -158,6 +158,11 @@ void RIFF::File::setChunkData(uint i, const ByteVector &data) d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding; } +void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data) +{ + setChunkData(name, data, false); +} + void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate) { if(d->chunks.size() == 0) { diff --git a/taglib/riff/rifffile.h b/taglib/riff/rifffile.h index 274549ae..6b8fe197 100644 --- a/taglib/riff/rifffile.h +++ b/taglib/riff/rifffile.h @@ -102,17 +102,27 @@ namespace TagLib { */ void setChunkData(uint i, const ByteVector &data); + /*! + * Sets the data for the chunk \a name to \a data. If a chunk with the + * given name already exists it will be overwritten, otherwise it will be + * created after the existing chunks. + * + * \warning This will update the file immediately. + */ + void setChunkData(const ByteVector &name, const ByteVector &data); + /*! * Sets the data for the chunk \a name to \a data. If a chunk with the * given name already exists it will be overwritten, otherwise it will be * created after the existing chunks. * * \note If \a alwaysCreate is true, a new chunk is created regardless of - * existence of chunk \a name. It should be used for only "LIST" chunks. + * whether or not the chunk \a name exists. It should only be used for + * "LIST" chunks. * * \warning This will update the file immediately. */ - void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate = false); + void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate); /*! * Removes the specified chunk. From bb5d3f0600ee4f9e87c0aa9c6ea5820e2ecf934a Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 12:45:14 +0900 Subject: [PATCH 08/33] Changed some class names --- taglib/toolkit/trefcountptr.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h index eb84e178..fb01de37 100644 --- a/taglib/toolkit/trefcountptr.h +++ b/taglib/toolkit/trefcountptr.h @@ -77,15 +77,15 @@ namespace TagLib { // Counter base class. Provides a reference counter. - class counter_base + class CounterBase { public: - counter_base() + CounterBase() : count(1) { } - virtual ~counter_base() + virtual ~CounterBase() { } @@ -142,10 +142,10 @@ namespace TagLib { // Counter impl class. Provides a dynamic deleter. template - class counter_impl : public counter_base + class CounterImpl : public CounterBase { public: - counter_impl(U *p) + CounterImpl(U *p) : p(p) { } @@ -167,7 +167,7 @@ namespace TagLib { public: template explicit RefCountPtr(U *p) - : counter(new counter_impl(p)) + : counter(new CounterImpl(p)) { } @@ -184,7 +184,7 @@ namespace TagLib { T *get() const { - return static_cast*>(counter)->get(); + return static_cast*>(counter)->get(); } long use_count() const @@ -203,7 +203,7 @@ namespace TagLib { if(get() != p) { counter->release(); - counter = new counter_impl(p); + counter = new CounterImpl(p); } } @@ -245,7 +245,7 @@ namespace TagLib { } private: - counter_base *counter; + CounterBase *counter; }; } #endif // TAGLIB_USE_CXX11 From 66f5f396ffabc65ab0e01b3078fcfa8463bfe2e6 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 21:41:23 +0900 Subject: [PATCH 09/33] Use shared_ptr if possible regardless of C++11 support --- CMakeLists.txt | 5 ---- ConfigureChecks.cmake | 25 ++++++++++++++++--- config-taglib.h.cmake | 4 +++ taglib/toolkit/trefcountptr.h | 46 ++++++++++++++++++----------------- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e56978f5..1f29e463 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,6 @@ else() endif() OPTION(ENABLE_STATIC_RUNTIME "Visual Studio, link with runtime statically" OFF) -option(ENABLE_CXX11 "Enable C++11 features" OFF) -if(ENABLE_CXX11) - add_definitions(-DTAGLIB_USE_CXX11) -endif() - option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF) if(VISIBILITY_HIDDEN) add_definitions (-fvisibility=hidden) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index e4a6d1fa..ec0da6d1 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -9,15 +9,32 @@ include(CheckCXXSourceCompiles) # check for libz using the cmake supplied FindZLIB.cmake find_package(ZLIB) if(ZLIB_FOUND) - set(HAVE_ZLIB 1) + set(HAVE_ZLIB 1) else() - set(HAVE_ZLIB 0) + set(HAVE_ZLIB 0) endif() +# Determine where shared_ptr is defined regardless of C++11 support. + +check_cxx_source_compiles(" + #include + int main() { std::tr1::shared_ptr x; return 0; } +" HAVE_STD_SHARED_PTR) + +check_cxx_source_compiles(" + #include + int main() { std::tr1::shared_ptr x; return 0; } +" HAVE_TR1_SHARED_PTR) + +check_cxx_source_compiles(" + #include + int main() { boost::shared_ptr x; return 0; } +" HAVE_BOOST_SHARED_PTR) + set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) - message(STATUS "CppUnit not found, disabling tests.") - set(BUILD_TESTS OFF) + message(STATUS "CppUnit not found, disabling tests.") + set(BUILD_TESTS OFF) endif() diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index 9c2f487d..8ce6798b 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -3,6 +3,10 @@ /* Define if you have libz */ #cmakedefine HAVE_ZLIB 1 +#cmakedefine HAVE_STD_SHARED_PTR 1 +#cmakedefine HAVE_TR1_SHARED_PTR 1 +#cmakedefine HAVE_BOOST_SHARED_PTR 1 + #cmakedefine NO_ITUNES_HACKS 1 #cmakedefine WITH_ASF 1 #cmakedefine WITH_MP4 1 diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h index fb01de37..492afcd5 100644 --- a/taglib/toolkit/trefcountptr.h +++ b/taglib/toolkit/trefcountptr.h @@ -26,10 +26,31 @@ #ifndef TAGLIB_REFCOUNTPTR_H #define TAGLIB_REFCOUNTPTR_H -// TAGLIB_USE_CXX11 determines whether or not to enable C++11 features. +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#ifdef TAGLIB_USE_CXX11 +#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. +/*! + * \internal + * This is just used as a smart pointer for shared classes in TagLib. + * + * \warning This is not part of the TagLib public API! + */ + +// RefCountPtr is just an alias of shared_ptr if it is available. + +#if defined(HAVE_STD_SHARED_PTR) # include +# define RefCountPtr std::tr1::shared_ptr + +#elif defined(HAVE_TR1_SHARED_PTR) +# include +# define RefCountPtr std::tr1::shared_ptr + +#elif defined(HAVE_BOOST_SHARED_PTR) +# include +# define RefCountPtr boost::shared_ptr #else # ifdef __APPLE__ @@ -46,29 +67,10 @@ # include # define TAGLIB_ATOMIC_GCC # endif -#endif - -#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. - -/*! - * \internal - * This is just used as a smart pointer for shared classes in TagLib. - * - * \warning This is not part of the TagLib public API! - */ - -#ifdef TAGLIB_USE_CXX11 - - // RefCountPtr is just an alias of std::shared_ptr if C++11 is available. -# define RefCountPtr std::shared_ptr - - // Workaround for the fact that some compilers don't support the template aliases. - -#else namespace TagLib { - // RefCountPtr mimics std::shared_ptr if C++11 is not available. + // RefCountPtr mimics std::shared_ptr if it is not available. template class RefCountPtr From 1f4e06ea7c60e0a72f04290abf6f57db803f3a12 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 22:54:56 +0900 Subject: [PATCH 10/33] Revert changes concerning the smart pointer --- ConfigureChecks.cmake | 25 +--- config-taglib.h.cmake | 4 - taglib/CMakeLists.txt | 5 - taglib/asf/asfattribute.cpp | 24 +-- taglib/asf/asfattribute.h | 2 +- taglib/asf/asfpicture.cpp | 14 +- taglib/asf/asfpicture.h | 8 +- taglib/fileref.cpp | 66 ++++----- taglib/fileref.h | 2 +- taglib/mp4/mp4coverart.cpp | 14 +- taglib/mp4/mp4coverart.h | 2 +- taglib/mp4/mp4item.cpp | 32 ++-- taglib/mp4/mp4item.h | 2 +- taglib/mpeg/mpegheader.cpp | 17 ++- taglib/mpeg/mpegheader.h | 3 +- taglib/toolkit/taglib.h | 66 ++++++++- taglib/toolkit/tbytevector.cpp | 65 +++++++-- taglib/toolkit/tbytevector.h | 6 +- taglib/toolkit/tiostream.h | 5 - taglib/toolkit/tlist.h | 4 +- taglib/toolkit/tlist.tcc | 52 +++---- taglib/toolkit/tmap.h | 5 +- taglib/toolkit/tmap.tcc | 47 +++--- taglib/toolkit/trefcountptr.h | 257 --------------------------------- taglib/toolkit/tstring.cpp | 59 ++++++-- taglib/toolkit/tstring.h | 6 +- 26 files changed, 329 insertions(+), 463 deletions(-) delete mode 100644 taglib/toolkit/trefcountptr.h diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index ec0da6d1..e4a6d1fa 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -9,32 +9,15 @@ include(CheckCXXSourceCompiles) # check for libz using the cmake supplied FindZLIB.cmake find_package(ZLIB) if(ZLIB_FOUND) - set(HAVE_ZLIB 1) + set(HAVE_ZLIB 1) else() - set(HAVE_ZLIB 0) + set(HAVE_ZLIB 0) endif() -# Determine where shared_ptr is defined regardless of C++11 support. - -check_cxx_source_compiles(" - #include - int main() { std::tr1::shared_ptr x; return 0; } -" HAVE_STD_SHARED_PTR) - -check_cxx_source_compiles(" - #include - int main() { std::tr1::shared_ptr x; return 0; } -" HAVE_TR1_SHARED_PTR) - -check_cxx_source_compiles(" - #include - int main() { boost::shared_ptr x; return 0; } -" HAVE_BOOST_SHARED_PTR) - set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) - message(STATUS "CppUnit not found, disabling tests.") - set(BUILD_TESTS OFF) + message(STATUS "CppUnit not found, disabling tests.") + set(BUILD_TESTS OFF) endif() diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index 8ce6798b..9c2f487d 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -3,10 +3,6 @@ /* Define if you have libz */ #cmakedefine HAVE_ZLIB 1 -#cmakedefine HAVE_STD_SHARED_PTR 1 -#cmakedefine HAVE_TR1_SHARED_PTR 1 -#cmakedefine HAVE_BOOST_SHARED_PTR 1 - #cmakedefine NO_ITUNES_HACKS 1 #cmakedefine WITH_ASF 1 #cmakedefine WITH_MP4 1 diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index dab3430e..a940caf5 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -51,7 +51,6 @@ set(tag_HDRS toolkit/tmap.tcc toolkit/tpropertymap.h toolkit/tbyteswap.h - toolkit/trefcountptr.h mpeg/mpegfile.h mpeg/mpegproperties.h mpeg/mpegheader.h @@ -312,10 +311,6 @@ if(ZLIB_FOUND) target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() -if(WIN32 AND NOT TAGLIB_STATIC) - target_link_libraries(tag shlwapi.lib) -endif() - set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} diff --git a/taglib/asf/asfattribute.cpp b/taglib/asf/asfattribute.cpp index 4ba2689b..2cfada7b 100644 --- a/taglib/asf/asfattribute.cpp +++ b/taglib/asf/asfattribute.cpp @@ -34,7 +34,7 @@ using namespace TagLib; -class ASF::Attribute::AttributePrivate +class ASF::Attribute::AttributePrivate : public RefCounter { public: AttributePrivate() @@ -60,71 +60,77 @@ public: //////////////////////////////////////////////////////////////////////////////// ASF::Attribute::Attribute() - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = UnicodeType; } ASF::Attribute::Attribute(const ASF::Attribute &other) : d(other.d) { + d->ref(); } ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) { + if(d->deref()) + delete d; d = other.d; + d->ref(); return *this; } ASF::Attribute::~Attribute() { + if(d->deref()) + delete d; } ASF::Attribute::Attribute(const String &value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = UnicodeType; d->stringValue = value; } ASF::Attribute::Attribute(const ByteVector &value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = BytesType; d->byteVectorValue = value; } ASF::Attribute::Attribute(const ASF::Picture &value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = BytesType; d->pictureValue = value; } ASF::Attribute::Attribute(unsigned int value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = DWordType; d->intValue = value; } ASF::Attribute::Attribute(unsigned long long value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = QWordType; d->longLongValue = value; } ASF::Attribute::Attribute(unsigned short value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = WordType; d->shortValue = value; } ASF::Attribute::Attribute(bool value) - : d(new AttributePrivate()) { + d = new AttributePrivate; d->type = BoolType; d->boolValue = value; } diff --git a/taglib/asf/asfattribute.h b/taglib/asf/asfattribute.h index ca26aec3..54eb0c7d 100644 --- a/taglib/asf/asfattribute.h +++ b/taglib/asf/asfattribute.h @@ -194,7 +194,7 @@ namespace TagLib ByteVector render(const String &name, int kind = 0) const; class AttributePrivate; - RefCountPtr d; + AttributePrivate *d; }; } diff --git a/taglib/asf/asfpicture.cpp b/taglib/asf/asfpicture.cpp index 82a38b6b..c36ffa3a 100644 --- a/taglib/asf/asfpicture.cpp +++ b/taglib/asf/asfpicture.cpp @@ -35,7 +35,7 @@ using namespace TagLib; -class ASF::Picture::PicturePrivate +class ASF::Picture::PicturePrivate : public RefCounter { public: bool valid; @@ -50,18 +50,21 @@ public: //////////////////////////////////////////////////////////////////////////////// ASF::Picture::Picture() - : d(new PicturePrivate()) { + d = new PicturePrivate(); d->valid = true; } ASF::Picture::Picture(const Picture& other) : d(other.d) { + d->ref(); } ASF::Picture::~Picture() { + if(d->deref()) + delete d; } bool ASF::Picture::isValid() const @@ -118,7 +121,12 @@ int ASF::Picture::dataSize() const ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other) { - d = other.d; + if(other.d != d) { + if(d->deref()) + delete d; + d = other.d; + d->ref(); + } return *this; } diff --git a/taglib/asf/asfpicture.h b/taglib/asf/asfpicture.h index aa838974..aa0a060c 100644 --- a/taglib/asf/asfpicture.h +++ b/taglib/asf/asfpicture.h @@ -207,10 +207,10 @@ namespace TagLib static Picture fromInvalid(); friend class Attribute; #endif - private: - class PicturePrivate; - RefCountPtr d; - }; + private: + class PicturePrivate; + PicturePrivate *d; + }; } } diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index f3b4ef3c..859f3155 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -31,10 +31,6 @@ #include #endif -#ifdef _WIN32 -# include -#endif - #include #include #include @@ -61,12 +57,15 @@ using namespace TagLib; -class FileRef::FileRefPrivate +class FileRef::FileRefPrivate : public RefCounter { public: - FileRefPrivate(File *f) : file(f) {} + FileRefPrivate(File *f) : RefCounter(), file(f) {} + ~FileRefPrivate() { + delete file; + } - RefCountPtr file; + File *file; static List fileTypeResolvers; }; @@ -77,28 +76,30 @@ List FileRef::FileRefPrivate::fileTypeResolve //////////////////////////////////////////////////////////////////////////////// FileRef::FileRef() - : d(new FileRefPrivate(0)) { + d = new FileRefPrivate(0); } -FileRef::FileRef( - FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) - : d(new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle))) +FileRef::FileRef(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) { + d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle)); } FileRef::FileRef(File *file) - : d(new FileRefPrivate(file)) { + d = new FileRefPrivate(file); } -FileRef::FileRef(const FileRef &ref) - : d(ref.d) +FileRef::FileRef(const FileRef &ref) : d(ref.d) { + d->ref(); } FileRef::~FileRef() { + if(d->deref()) + delete d; } Tag *FileRef::tag() const @@ -121,7 +122,7 @@ AudioProperties *FileRef::audioProperties() const File *FileRef::file() const { - return d->file.get(); + return d->file; } bool FileRef::save() @@ -181,7 +182,15 @@ bool FileRef::isNull() const FileRef &FileRef::operator=(const FileRef &ref) { + if(&ref == this) + return *this; + + if(d->deref()) + delete d; + d = ref.d; + d->ref(); + return *this; } @@ -209,36 +218,21 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, // Ok, this is really dumb for now, but it works for testing. - String ext; + String s; #ifdef _WIN32 - // Avoids direct conversion from FileName to String - // because String can't accept non-Latin-1 string in char array. - - if(!fileName.wstr().empty()) { - const wchar_t *pext = PathFindExtensionW(fileName.wstr().c_str()); - if(*pext == L'.') - ext = String(pext + 1).upper(); - } - else { - const char *pext = PathFindExtensionA(fileName.str().c_str()); - if(*pext == '.') - ext = String(pext + 1).upper(); - } + s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName); #else - { - String s = fileName; - const int pos = s.rfind("."); - if(pos != -1) - ext = s.substr(pos + 1).upper(); - } + s = fileName; #endif // If this list is updated, the method defaultFileExtensions() should also be // updated. However at some point that list should be created at the same time // that a default file type resolver is created. - if(!ext.isEmpty()) { + int pos = s.rfind("."); + if(pos != -1) { + String ext = s.substr(pos + 1).upper(); if(ext == "MP3") return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OGG") diff --git a/taglib/fileref.h b/taglib/fileref.h index 907727c7..0f0c21a4 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -255,7 +255,7 @@ namespace TagLib { private: class FileRefPrivate; - RefCountPtr d; + FileRefPrivate *d; }; } // namespace TagLib diff --git a/taglib/mp4/mp4coverart.cpp b/taglib/mp4/mp4coverart.cpp index 5b6e6e23..928e3c4a 100644 --- a/taglib/mp4/mp4coverart.cpp +++ b/taglib/mp4/mp4coverart.cpp @@ -33,35 +33,43 @@ using namespace TagLib; -class MP4::CoverArt::CoverArtPrivate +class MP4::CoverArt::CoverArtPrivate : public RefCounter { public: - CoverArtPrivate() : format(MP4::CoverArt::JPEG) {} + CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {} Format format; ByteVector data; }; MP4::CoverArt::CoverArt(Format format, const ByteVector &data) - : d(new CoverArtPrivate()) { + d = new CoverArtPrivate; d->format = format; d->data = data; } MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d) { + d->ref(); } MP4::CoverArt & MP4::CoverArt::operator=(const CoverArt &item) { + if(d->deref()) { + delete d; + } d = item.d; + d->ref(); return *this; } MP4::CoverArt::~CoverArt() { + if(d->deref()) { + delete d; + } } MP4::CoverArt::Format diff --git a/taglib/mp4/mp4coverart.h b/taglib/mp4/mp4coverart.h index b6b44c49..64115b45 100644 --- a/taglib/mp4/mp4coverart.h +++ b/taglib/mp4/mp4coverart.h @@ -63,7 +63,7 @@ namespace TagLib { private: class CoverArtPrivate; - RefCountPtr d; + CoverArtPrivate *d; }; typedef List CoverArtList; diff --git a/taglib/mp4/mp4item.cpp b/taglib/mp4/mp4item.cpp index 6a303652..af2cc65c 100644 --- a/taglib/mp4/mp4item.cpp +++ b/taglib/mp4/mp4item.cpp @@ -33,10 +33,10 @@ using namespace TagLib; -class MP4::Item::ItemPrivate +class MP4::Item::ItemPrivate : public RefCounter { public: - ItemPrivate() : valid(true), atomDataType(TypeUndefined) {} + ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {} bool valid; AtomDataType atomDataType; @@ -54,78 +54,86 @@ public: }; MP4::Item::Item() - : d(new ItemPrivate()) { + d = new ItemPrivate; d->valid = false; } MP4::Item::Item(const Item &item) : d(item.d) { + d->ref(); } MP4::Item & MP4::Item::operator=(const Item &item) { + if(d->deref()) { + delete d; + } d = item.d; + d->ref(); return *this; } MP4::Item::~Item() { + if(d->deref()) { + delete d; + } } MP4::Item::Item(bool value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_bool = value; } MP4::Item::Item(int value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_int = value; } MP4::Item::Item(uchar value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_byte = value; } MP4::Item::Item(uint value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_uint = value; } MP4::Item::Item(long long value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_longlong = value; } MP4::Item::Item(int value1, int value2) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_intPair.first = value1; d->m_intPair.second = value2; } MP4::Item::Item(const ByteVectorList &value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_byteVectorList = value; } MP4::Item::Item(const StringList &value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_stringList = value; } MP4::Item::Item(const MP4::CoverArtList &value) - : d(new ItemPrivate()) { + d = new ItemPrivate; d->m_coverArtList = value; } diff --git a/taglib/mp4/mp4item.h b/taglib/mp4/mp4item.h index 3b4e23cd..be7aa1a1 100644 --- a/taglib/mp4/mp4item.h +++ b/taglib/mp4/mp4item.h @@ -73,7 +73,7 @@ namespace TagLib { private: class ItemPrivate; - RefCountPtr d; + ItemPrivate *d; }; } diff --git a/taglib/mpeg/mpegheader.cpp b/taglib/mpeg/mpegheader.cpp index bc98f4c9..c715dbc1 100644 --- a/taglib/mpeg/mpegheader.cpp +++ b/taglib/mpeg/mpegheader.cpp @@ -33,7 +33,7 @@ using namespace TagLib; -class MPEG::Header::HeaderPrivate +class MPEG::Header::HeaderPrivate : public RefCounter { public: HeaderPrivate() : @@ -68,18 +68,20 @@ public: //////////////////////////////////////////////////////////////////////////////// MPEG::Header::Header(const ByteVector &data) - : d(new HeaderPrivate()) { + d = new HeaderPrivate; parse(data); } -MPEG::Header::Header(const Header &h) - : d(h.d) +MPEG::Header::Header(const Header &h) : d(h.d) { + d->ref(); } MPEG::Header::~Header() { + if (d->deref()) + delete d; } bool MPEG::Header::isValid() const @@ -144,7 +146,14 @@ int MPEG::Header::samplesPerFrame() const MPEG::Header &MPEG::Header::operator=(const Header &h) { + if(&h == this) + return *this; + + if(d->deref()) + delete d; + d = h.d; + d->ref(); return *this; } diff --git a/taglib/mpeg/mpegheader.h b/taglib/mpeg/mpegheader.h index 7a352ed7..020ebd06 100644 --- a/taglib/mpeg/mpegheader.h +++ b/taglib/mpeg/mpegheader.h @@ -27,7 +27,6 @@ #define TAGLIB_MPEGHEADER_H #include "taglib_export.h" -#include "trefcountptr.h" namespace TagLib { @@ -159,7 +158,7 @@ namespace TagLib { void parse(const ByteVector &data); class HeaderPrivate; - RefCountPtr d; + HeaderPrivate *d; }; } } diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index 03d16724..dd4ee69d 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -45,11 +45,23 @@ #include #include -#ifdef _WIN32 -# if !defined(NOMINMAX) -# define NOMINMAX -# endif -# include +#ifdef __APPLE__ +# include +# define TAGLIB_ATOMIC_MAC +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if !defined(NOMINMAX) +# define NOMINMAX +# endif +# include +# define TAGLIB_ATOMIC_WIN +#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ + && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ + && !defined(__INTEL_COMPILER) +# define TAGLIB_ATOMIC_GCC +#elif defined(__ia64) && defined(__INTEL_COMPILER) +# include +# define TAGLIB_ATOMIC_GCC #endif // Check the widths of integral types. @@ -104,6 +116,50 @@ namespace TagLib { * so I'm providing something here that should be constant. */ typedef std::basic_string wstring; + +#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. + /*! + * \internal + * This is just used as a base class for shared classes in TagLib. + * + * \warning This is not part of the TagLib public API! + */ + + class RefCounter + { + public: + RefCounter() : refCount(1) {} + +#ifdef TAGLIB_ATOMIC_MAC + void ref() { OSAtomicIncrement32Barrier(const_cast(&refCount)); } + bool deref() { return ! OSAtomicDecrement32Barrier(const_cast(&refCount)); } + int32_t count() { return refCount; } + private: + volatile int32_t refCount; +#elif defined(TAGLIB_ATOMIC_WIN) + void ref() { InterlockedIncrement(&refCount); } + bool deref() { return ! InterlockedDecrement(&refCount); } + long count() { return refCount; } + private: + volatile long refCount; +#elif defined(TAGLIB_ATOMIC_GCC) + void ref() { __sync_add_and_fetch(&refCount, 1); } + bool deref() { return ! __sync_sub_and_fetch(&refCount, 1); } + int count() { return refCount; } + private: + volatile int refCount; +#else + void ref() { refCount++; } + bool deref() { return ! --refCount; } + int count() { return refCount; } + private: + uint refCount; +#endif + + }; + +#endif // DO_NOT_DOCUMENT + } /*! diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index aa76d6bf..ca65cfaa 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -236,7 +236,7 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst) return ByteVector(reinterpret_cast(&value), size); } -class DataPrivate +class DataPrivate : public RefCounter { public: DataPrivate() @@ -262,39 +262,45 @@ public: std::vector data; }; -class ByteVector::ByteVectorPrivate +class ByteVector::ByteVectorPrivate : public RefCounter { public: ByteVectorPrivate() - : data(new DataPrivate()) + : RefCounter() + , data(new DataPrivate()) , offset(0) , length(0) { } - ByteVectorPrivate(RefCountPtr d, uint o, uint l) - : data(d->data) + ByteVectorPrivate(ByteVectorPrivate *d, uint o, uint l) + : RefCounter() + , data(d->data) , offset(d->offset + o) , length(l) { + data->ref(); } ByteVectorPrivate(const std::vector &v, uint o, uint l) - : data(new DataPrivate(v, o, l)) + : RefCounter() + , data(new DataPrivate(v, o, l)) , offset(0) , length(l) { } ByteVectorPrivate(uint l, char c) - : data(new DataPrivate(l, c)) + : RefCounter() + , data(new DataPrivate(l, c)) , offset(0) , length(l) { } ByteVectorPrivate(const char *s, uint l) - : data(new DataPrivate(s, s + l)) + : RefCounter() + , data(new DataPrivate(s, s + l)) , offset(0) , length(l) { @@ -302,25 +308,34 @@ public: void detach() { - if(!data.unique()) { - data.reset(new DataPrivate(data->data, offset, length)); + if(data->count() > 1) { + data->deref(); + data = new DataPrivate(data->data, offset, length); offset = 0; } } ~ByteVectorPrivate() { + if(data->deref()) + delete data; } ByteVectorPrivate &operator=(const ByteVectorPrivate &x) { if(&x != this) + { + if(data->deref()) + delete data; + data = x.data; + data->ref(); + } return *this; } - RefCountPtr data; + DataPrivate *data; uint offset; uint length; }; @@ -371,11 +386,13 @@ ByteVector::ByteVector(uint size, char value) ByteVector::ByteVector(const ByteVector &v) : d(v.d) { + d->ref(); } ByteVector::ByteVector(const ByteVector &v, uint offset, uint length) : d(new ByteVectorPrivate(v.d, offset, length)) { + d->ref(); } ByteVector::ByteVector(char c) @@ -395,6 +412,8 @@ ByteVector::ByteVector(const char *data) ByteVector::~ByteVector() { + if(d->deref()) + delete d; } ByteVector &ByteVector::setData(const char *s, uint length) @@ -544,7 +563,10 @@ ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &wit } // replace private data: - d.reset(newData); + if(d->deref()) + delete d; + + d = newData; return *this; } @@ -743,7 +765,14 @@ ByteVector ByteVector::operator+(const ByteVector &v) const ByteVector &ByteVector::operator=(const ByteVector &v) { + if(&v == this) + return *this; + + if(d->deref()) + delete d; + d = v.d; + d->ref(); return *this; } @@ -779,10 +808,16 @@ ByteVector ByteVector::toHex() const void ByteVector::detach() { - d->detach(); + if(d->data->count() > 1) { + d->data->deref(); + d->data = new DataPrivate(d->data->data, d->offset, d->length); + d->offset = 0; + } - if(!d.unique()) - d.reset(new ByteVectorPrivate(d->data->data, d->offset, d->length)); + if(d->count() > 1) { + d->deref(); + d = new ByteVectorPrivate(d->data->data, d->offset, d->length); + } } } diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index cf7f66d5..ca810130 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -26,9 +26,9 @@ #ifndef TAGLIB_BYTEVECTOR_H #define TAGLIB_BYTEVECTOR_H -#include "taglib_export.h" #include "taglib.h" -#include "trefcountptr.h" +#include "taglib_export.h" + #include #include @@ -446,7 +446,7 @@ namespace TagLib { private: class ByteVectorPrivate; - RefCountPtr d; + ByteVectorPrivate *d; }; } diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index ce1a0d0d..3e7de22a 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -38,13 +38,8 @@ namespace TagLib { public: FileName(const wchar_t *name) : m_wname(name) {} FileName(const char *name) : m_name(name) {} - operator const wchar_t *() const { return m_wname.c_str(); } operator const char *() const { return m_name.c_str(); } - - const std::wstring &wstr() const { return m_wname; } - const std::string &str() const { return m_name; } - private: std::string m_name; std::wstring m_wname; diff --git a/taglib/toolkit/tlist.h b/taglib/toolkit/tlist.h index 535b374f..0099dad5 100644 --- a/taglib/toolkit/tlist.h +++ b/taglib/toolkit/tlist.h @@ -27,7 +27,7 @@ #define TAGLIB_LIST_H #include "taglib.h" -#include "trefcountptr.h" + #include namespace TagLib { @@ -243,7 +243,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class ListPrivate; - RefCountPtr > d; + ListPrivate *d; #endif }; diff --git a/taglib/toolkit/tlist.tcc b/taglib/toolkit/tlist.tcc index 17d68a5a..37817f05 100644 --- a/taglib/toolkit/tlist.tcc +++ b/taglib/toolkit/tlist.tcc @@ -38,7 +38,7 @@ namespace TagLib { // A base for the generic and specialized private class types. New // non-templatized members should be added here. -class ListPrivateBase +class ListPrivateBase : public RefCounter { public: ListPrivateBase() : autoDelete(false) {} @@ -53,9 +53,8 @@ template class List::ListPrivate : public ListPrivateBase public: ListPrivate() : ListPrivateBase() {} ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} - void clear() { - std::list().swap(list); + list.clear(); } std::list list; }; @@ -69,27 +68,18 @@ template class List::ListPrivate : public ListPrivateBase public: ListPrivate() : ListPrivateBase() {} ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} - ~ListPrivate() { - deletePointers(); + clear(); } - void clear() { - deletePointers(); - std::list().swap(list); + if(autoDelete) { + typename std::list::const_iterator it = list.begin(); + for(; it != list.end(); ++it) + delete *it; + } + list.clear(); } - std::list list; - -private: - void deletePointers() { - if(!autoDelete) - return; - - typename std::list::const_iterator it = list.begin(); - for(; it != list.end(); ++it) - delete *it; - } }; //////////////////////////////////////////////////////////////////////////////// @@ -98,19 +88,21 @@ private: template List::List() - : d(new ListPrivate()) { + d = new ListPrivate; } template -List::List(const List &l) - : d(l.d) +List::List(const List &l) : d(l.d) { + d->ref(); } template List::~List() { + if(d->deref()) + delete d; } template @@ -187,7 +179,7 @@ template List &List::prepend(const List &l) { detach(); - d->list.insert(d->list.begin(), l.d->list.begin(), l.d->list.end()); + d->list.insert(d->list.begin(), l.begin(), l.end()); return *this; } @@ -200,7 +192,7 @@ List &List::clear() } template -uint List::size() const +TagLib::uint List::size() const { return d->list.size(); } @@ -292,7 +284,13 @@ const T &List::operator[](uint i) const template List &List::operator=(const List &l) { + if(&l == this) + return *this; + + if(d->deref()) + delete d; d = l.d; + d->ref(); return *this; } @@ -315,8 +313,10 @@ bool List::operator!=(const List &l) const template void List::detach() { - if(!d.unique()) - d.reset(new ListPrivate(d->list)); + if(d->count() > 1) { + d->deref(); + d = new ListPrivate(d->list); + } } } // namespace TagLib diff --git a/taglib/toolkit/tmap.h b/taglib/toolkit/tmap.h index b5748e66..a7d99303 100644 --- a/taglib/toolkit/tmap.h +++ b/taglib/toolkit/tmap.h @@ -26,10 +26,9 @@ #ifndef TAGLIB_MAP_H #define TAGLIB_MAP_H -#include "taglib.h" -#include "trefcountptr.h" #include +#include "taglib.h" namespace TagLib { @@ -186,7 +185,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class MapPrivate; - RefCountPtr > d; + MapPrivate *d; #endif }; diff --git a/taglib/toolkit/tmap.tcc b/taglib/toolkit/tmap.tcc index 783f99cc..0f2b9933 100644 --- a/taglib/toolkit/tmap.tcc +++ b/taglib/toolkit/tmap.tcc @@ -31,49 +31,36 @@ namespace TagLib { template template -class Map::MapPrivate +class Map::MapPrivate : public RefCounter { public: - MapPrivate() {} - + MapPrivate() : RefCounter() {} #ifdef WANT_CLASS_INSTANTIATION_OF_MAP - - MapPrivate(const std::map &m) : RefCounter(), map(m) {} - - void clear() { - std::map().swap(map); - } - + MapPrivate(const std::map& m) : RefCounter(), map(m) {} std::map map; - #else - - MapPrivate(const std::map& m) : map(m) {} - - void clear() { - std::map().swap(map); - } - + MapPrivate(const std::map& m) : RefCounter(), map(m) {} std::map map; - #endif }; template Map::Map() - : d(new MapPrivate()) { + d = new MapPrivate; } template -Map::Map(const Map &m) - : d(m.d) +Map::Map(const Map &m) : d(m.d) { + d->ref(); } template Map::~Map() { + if(d->deref()) + delete(d); } template @@ -162,7 +149,7 @@ Map &Map::erase(const Key &key) } template -uint Map::size() const +TagLib::uint Map::size() const { return d->map.size(); } @@ -183,7 +170,13 @@ 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(); return *this; } @@ -194,8 +187,10 @@ Map &Map::operator=(const Map &m) template void Map::detach() { - if(!d.unique()) - d.reset(new MapPrivate(d->map)); + if(d->count() > 1) { + d->deref(); + d = new MapPrivate(d->map); + } } -} // namespace TagLib \ No newline at end of file +} // namespace TagLib diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h deleted file mode 100644 index 492afcd5..00000000 --- a/taglib/toolkit/trefcountptr.h +++ /dev/null @@ -1,257 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_REFCOUNTPTR_H -#define TAGLIB_REFCOUNTPTR_H - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. -/*! - * \internal - * This is just used as a smart pointer for shared classes in TagLib. - * - * \warning This is not part of the TagLib public API! - */ - -// RefCountPtr is just an alias of shared_ptr if it is available. - -#if defined(HAVE_STD_SHARED_PTR) -# include -# define RefCountPtr std::tr1::shared_ptr - -#elif defined(HAVE_TR1_SHARED_PTR) -# include -# define RefCountPtr std::tr1::shared_ptr - -#elif defined(HAVE_BOOST_SHARED_PTR) -# include -# define RefCountPtr boost::shared_ptr - -#else -# ifdef __APPLE__ -# include -# define TAGLIB_ATOMIC_MAC -# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define TAGLIB_ATOMIC_WIN -# elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ - && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ - defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ - && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -# elif defined(__ia64) && defined(__INTEL_COMPILER) -# include -# define TAGLIB_ATOMIC_GCC -# endif - -namespace TagLib { - - // RefCountPtr mimics std::shared_ptr if it is not available. - - template - class RefCountPtr - { - private: - - // Counter base class. Provides a reference counter. - - class CounterBase - { - public: - CounterBase() - : count(1) - { - } - - virtual ~CounterBase() - { - } - - void addref() - { - increment(&count); - } - - void release() - { - if(decrement(&count) == 0) { - dispose(); - delete this; - } - } - - long use_count() const - { - return static_cast(count); - } - - virtual void dispose() = 0; - - private: -# if defined(TAGLIB_ATOMIC_MAC) - typedef volatile int32_t counter_t; - - inline static void increment(counter_t *c) { OSAtomicIncrement32Barrier(c); } - inline static counter_t decrement(counter_t *c) { return OSAtomicDecrement32Barrier(c); } - -# elif defined(TAGLIB_ATOMIC_WIN) - typedef volatile long counter_t; - - inline static void increment(counter_t *c) { InterlockedIncrement(c); } - inline static counter_t decrement(counter_t *c) { return InterlockedDecrement(c); } - -# elif defined(TAGLIB_ATOMIC_GCC) - typedef volatile int counter_t; - - inline static void increment(counter_t *c) { __sync_add_and_fetch(c, 1); } - inline static counter_t decrement(counter_t *c) { return __sync_sub_and_fetch(c, 1); } - -# else - typedef uint counter_t; - - inline static void increment(counter_t *c) { ++(*c) } - inline static counter_t decrement(counter_t *c) { return --(*c); } - -# endif - - counter_t count; - }; - - // Counter impl class. Provides a dynamic deleter. - - template - class CounterImpl : public CounterBase - { - public: - CounterImpl(U *p) - : p(p) - { - } - - virtual void dispose() - { - delete p; - } - - U *get() const - { - return p; - } - - private: - U *p; - }; - - public: - template - explicit RefCountPtr(U *p) - : counter(new CounterImpl(p)) - { - } - - RefCountPtr(const RefCountPtr &x) - { - counter = x.counter; - counter->addref(); - } - - ~RefCountPtr() - { - counter->release(); - } - - T *get() const - { - return static_cast*>(counter)->get(); - } - - long use_count() const - { - return counter->use_count(); - } - - bool unique() const - { - return (use_count() == 1); - } - - template - void reset(U *p) - { - if(get() != p) - { - counter->release(); - counter = new CounterImpl(p); - } - } - - RefCountPtr &operator=(const RefCountPtr &x) - { - if(get() != x.get()) - { - counter->release(); - - counter = x.counter; - counter->addref(); - } - return *this; - } - - T& operator*() const - { - return *get(); - } - - T* operator->() const - { - return get(); - } - - bool operator==(const RefCountPtr &x) const - { - return (get() == x.get()); - } - - bool operator!=(const RefCountPtr &x) const - { - return !operator==(x); - } - - operator bool() const - { - return (get() != 0); - } - - private: - CounterBase *counter; - }; -} -#endif // TAGLIB_USE_CXX11 - -#endif // DO_NOT_DOCUMENT - -#endif \ No newline at end of file diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 14abae2f..219d3daf 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -30,6 +30,7 @@ #include "tstringlist.h" #include "tbyteswap.h" +#include #include // Determine if the compiler supports codecvt. @@ -55,20 +56,23 @@ namespace { namespace TagLib { -class String::StringPrivate +class String::StringPrivate : public RefCounter { public: StringPrivate() + : RefCounter() { } StringPrivate(const wstring &s) - : data(s) + : RefCounter() + , data(s) { } StringPrivate(uint n, wchar_t c) - : data(static_cast(n), c) + : RefCounter() + , data(static_cast(n), c) { } @@ -95,6 +99,7 @@ String::String() String::String(const String &s) : d(s.d) { + d->ref(); } String::String(const std::string &s, Type t) @@ -177,6 +182,8 @@ String::String(const ByteVector &v, Type t) String::~String() { + if(d->deref()) + delete d; } std::string String::to8Bit(bool unicode) const @@ -609,13 +616,22 @@ String &String::operator+=(char c) String &String::operator=(const String &s) { + if(&s == this) + return *this; + + if(d->deref()) + delete d; d = s.d; + d->ref(); return *this; } String &String::operator=(const std::string &s) { - d.reset(new StringPrivate()); + if(d->deref()) + delete d; + + d = new StringPrivate; copyFromLatin1(s.c_str(), s.length()); return *this; @@ -623,33 +639,45 @@ String &String::operator=(const std::string &s) String &String::operator=(const wstring &s) { - d.reset(new StringPrivate(s)); + if(d->deref()) + delete d; + d = new StringPrivate(s); return *this; } String &String::operator=(const wchar_t *s) { - d.reset(new StringPrivate()); - copyFromUTF16(s, ::wcslen(s), WCharByteOrder); + if(d->deref()) + delete d; + d = new StringPrivate(s); return *this; } String &String::operator=(char c) { - d.reset(new StringPrivate(1, static_cast(c))); + if(d->deref()) + delete d; + + d = new StringPrivate(1, static_cast(c)); return *this; } String &String::operator=(wchar_t c) { - d.reset(new StringPrivate(1, static_cast(c))); + if(d->deref()) + delete d; + + d = new StringPrivate(1, static_cast(c)); return *this; } String &String::operator=(const char *s) { - d.reset(new StringPrivate()); + if(d->deref()) + delete d; + + d = new StringPrivate; copyFromLatin1(s, ::strlen(s)); return *this; @@ -657,7 +685,10 @@ String &String::operator=(const char *s) String &String::operator=(const ByteVector &v) { - d.reset(new StringPrivate()); + if(d->deref()) + delete d; + + d = new StringPrivate; copyFromLatin1(v.data(), v.size()); // If we hit a null in the ByteVector, shrink the string again. @@ -677,8 +708,10 @@ bool String::operator<(const String &s) const void String::detach() { - if(!d.unique()) - d.reset(new StringPrivate(d->data)); + if(d->count() > 1) { + d->deref(); + d = new StringPrivate(d->data); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index 652c6ca7..150d7c37 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -26,8 +26,12 @@ #ifndef TAGLIB_STRING_H #define TAGLIB_STRING_H +#include "taglib_export.h" +#include "taglib.h" #include "tbytevector.h" + #include +#include /*! * \relates TagLib::String @@ -481,7 +485,7 @@ namespace TagLib { static const Type WCharByteOrder; class StringPrivate; - RefCountPtr d; + StringPrivate *d; }; } From ccaac6c336858d398eb8638cd8f46cb1357c855c Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Wed, 17 Apr 2013 23:47:09 +0900 Subject: [PATCH 11/33] Fix improper string handling --- taglib/CMakeLists.txt | 4 ++++ taglib/fileref.cpp | 34 +++++++++++++++++++++++++++------- taglib/toolkit/tiostream.h | 5 +++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index a940caf5..63b88bb7 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -311,6 +311,10 @@ if(ZLIB_FOUND) target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() +if(WIN32 AND NOT TAGLIB_STATIC) + target_link_libraries(tag shlwapi.lib) +endif() + set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 859f3155..a6c96c07 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -28,9 +28,14 @@ ***************************************************************************/ #ifdef HAVE_CONFIG_H -#include +# include #endif +#ifdef _WIN32 +# include +#endif + + #include #include #include @@ -218,21 +223,36 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, // Ok, this is really dumb for now, but it works for testing. - String s; + String ext; #ifdef _WIN32 - s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName); + // Avoids direct conversion from FileName to String + // because String can't decode strings in local encodings properly. + + if(!fileName.wstr().empty()) { + const wchar_t *pext = PathFindExtensionW(fileName.wstr().c_str()); + if(*pext == L'.') + ext = String(pext + 1).upper(); + } + else { + const char *pext = PathFindExtensionA(fileName.str().c_str()); + if(*pext == '.') + ext = String(pext + 1).upper(); + } #else - s = fileName; + { + String s = fileName; + const int pos = s.rfind("."); + if(pos != -1) + ext = s.substr(pos + 1).upper(); + } #endif // If this list is updated, the method defaultFileExtensions() should also be // updated. However at some point that list should be created at the same time // that a default file type resolver is created. - int pos = s.rfind("."); - if(pos != -1) { - String ext = s.substr(pos + 1).upper(); + if(!ext.isEmpty()) { if(ext == "MP3") return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OGG") diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index 3e7de22a..1508e402 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -38,8 +38,13 @@ namespace TagLib { public: FileName(const wchar_t *name) : m_wname(name) {} FileName(const char *name) : m_name(name) {} + operator const wchar_t *() const { return m_wname.c_str(); } operator const char *() const { return m_name.c_str(); } + + const std::wstring &wstr() const { return m_wname; } + const std::string &str() const { return m_name; } + private: std::string m_name; std::wstring m_wname; From 1370a1cc83f2f7e7c482fb7f32f8795f8a77d6bb Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Thu, 18 Apr 2013 00:32:14 +0900 Subject: [PATCH 12/33] Detect header automatically --- ConfigureChecks.cmake | 7 +++++++ config-taglib.h.cmake | 3 +++ taglib/toolkit/tstring.cpp | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index e4a6d1fa..4b8f512e 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -14,6 +14,13 @@ else() set(HAVE_ZLIB 0) endif() +# Determine whether your compiler supports codecvt header. + +check_cxx_source_compiles(" + #include + int main() { std::codecvt_utf8_utf16 x; return 0; } +" HAVE_CODECVT) + set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index 9c2f487d..9fcc29a4 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -3,6 +3,9 @@ /* Define if you have libz */ #cmakedefine HAVE_ZLIB 1 +/* Defined if your compiler has header */ +#cmakedefine HAVE_CODECVT 1 + #cmakedefine NO_ITUNES_HACKS 1 #cmakedefine WITH_ASF 1 #cmakedefine WITH_MP4 1 diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 219d3daf..bb0b0b93 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -25,6 +25,10 @@ // This class assumes that std::basic_string has a contiguous and null-terminated buffer. +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "tstring.h" #include "tdebug.h" #include "tstringlist.h" @@ -33,15 +37,11 @@ #include #include -// Determine if the compiler supports codecvt. - -#if (defined(_MSC_VER) && _MSC_VER >= 1600) -# define TAGLIB_USE_CODECVT -#endif - -#ifdef TAGLIB_USE_CODECVT +#ifdef HAVE_CODECVT # include -typedef std::codecvt_utf8_utf16 utf8_utf16_t; +namespace { + typedef std::codecvt_utf8_utf16 utf8_utf16_t; +} #else # include "unicode.h" #endif @@ -202,7 +202,7 @@ std::string String::to8Bit(bool unicode) const else { s.resize(d->data.size() * 4 + 1); -#ifdef TAGLIB_USE_CODECVT +#ifdef HAVE_CODECVT std::mbstate_t st = 0; const wchar_t *source; @@ -371,7 +371,7 @@ ByteVector String::data(Type t) const { ByteVector v(size() * 4 + 1, 0); -#ifdef TAGLIB_USE_CODECVT +#ifdef HAVE_CODECVT std::mbstate_t st = 0; const wchar_t *source; @@ -730,7 +730,7 @@ void String::copyFromUTF8(const char *s, size_t length) { d->data.resize(length); -#ifdef TAGLIB_USE_CODECVT +#ifdef HAVE_CODECVT std::mbstate_t st = 0; const char *source; From 439f27640a408c3fd1b2958046333b12b6bc5524 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Thu, 18 Apr 2013 18:36:19 +0900 Subject: [PATCH 13/33] ByteVector::toUInt() takes offset and length --- taglib/ape/apefooter.cpp | 8 +- taglib/ape/apeitem.cpp | 4 +- taglib/ape/apeproperties.cpp | 31 ++++---- taglib/asf/asffile.cpp | 9 ++- taglib/asf/asfpicture.cpp | 2 +- taglib/flac/flacfile.cpp | 4 +- taglib/flac/flacpicture.cpp | 18 ++--- taglib/flac/flacproperties.cpp | 6 +- taglib/mp4/mp4atom.cpp | 4 +- taglib/mp4/mp4properties.cpp | 24 +++--- taglib/mp4/mp4tag.cpp | 28 +++---- taglib/mpc/mpcproperties.cpp | 30 ++++---- .../mpeg/id3v2/frames/popularimeterframe.cpp | 2 +- .../mpeg/id3v2/frames/relativevolumeframe.cpp | 2 +- taglib/mpeg/id3v2/id3v2frame.cpp | 6 +- taglib/mpeg/id3v2/id3v2synchdata.cpp | 2 +- taglib/mpeg/xingheader.cpp | 4 +- taglib/ogg/flac/oggflacfile.cpp | 6 +- taglib/ogg/oggpageheader.cpp | 6 +- taglib/ogg/opus/opusproperties.cpp | 6 +- taglib/ogg/speex/speexproperties.cpp | 14 ++-- taglib/ogg/vorbis/vorbisproperties.cpp | 12 +-- taglib/ogg/xiphcomment.cpp | 6 +- taglib/riff/aiff/aiffproperties.cpp | 6 +- taglib/riff/wav/infotag.cpp | 2 +- taglib/riff/wav/wavproperties.cpp | 10 +-- taglib/toolkit/tbyteswap.cpp | 2 +- taglib/toolkit/tbytevector.cpp | 76 ++++++++++++++----- taglib/toolkit/tbytevector.h | 61 ++++++++++++++- taglib/trueaudio/trueaudioproperties.cpp | 8 +- taglib/wavpack/wavpackproperties.cpp | 14 ++-- 31 files changed, 254 insertions(+), 159 deletions(-) diff --git a/taglib/ape/apefooter.cpp b/taglib/ape/apefooter.cpp index 68864901..539832ba 100644 --- a/taglib/ape/apefooter.cpp +++ b/taglib/ape/apefooter.cpp @@ -177,19 +177,19 @@ void APE::Footer::parse(const ByteVector &data) // Read the version number - d->version = data.mid(8, 4).toUInt(false); + d->version = data.toUInt(8, false); // Read the tag size - d->tagSize = data.mid(12, 4).toUInt(false); + d->tagSize = data.toUInt(12, false); // Read the item count - d->itemCount = data.mid(16, 4).toUInt(false); + d->itemCount = data.toUInt(16, false); // Read the flags - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(20, 4).toUInt(false))); + std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false))); d->headerPresent = flags[31]; d->footerPresent = !flags[30]; diff --git a/taglib/ape/apeitem.cpp b/taglib/ape/apeitem.cpp index 9d9647ec..b1670a65 100644 --- a/taglib/ape/apeitem.cpp +++ b/taglib/ape/apeitem.cpp @@ -229,8 +229,8 @@ void APE::Item::parse(const ByteVector &data) return; } - uint valueLength = data.mid(0, 4).toUInt(false); - uint flags = data.mid(4, 4).toUInt(false); + const uint valueLength = data.toUInt(0, false); + const uint flags = data.toUInt(4, false); d->key = String(data.mid(8), String::UTF8); diff --git a/taglib/ape/apeproperties.cpp b/taglib/ape/apeproperties.cpp index b4fcec6a..4940edea 100644 --- a/taglib/ape/apeproperties.cpp +++ b/taglib/ape/apeproperties.cpp @@ -125,10 +125,10 @@ void APE::Properties::read() // Then we read the header common for all versions of APE d->file->seek(offset); - ByteVector commonHeader=d->file->readBlock(6); + ByteVector commonHeader = d->file->readBlock(6); if(!commonHeader.startsWith("MAC ")) return; - d->version = commonHeader.mid(4).toUInt(false); + d->version = commonHeader.toUShort(4, false); if(d->version >= 3980) { analyzeCurrent(); @@ -182,7 +182,7 @@ void APE::Properties::analyzeCurrent() // Read the descriptor d->file->seek(2, File::Current); ByteVector descriptor = d->file->readBlock(44); - uint descriptorBytes = descriptor.mid(0,4).toUInt(false); + const uint descriptorBytes = descriptor.toUInt(0, false); if ((descriptorBytes - 52) > 0) d->file->seek(descriptorBytes - 52, File::Current); @@ -191,14 +191,14 @@ void APE::Properties::analyzeCurrent() ByteVector header = d->file->readBlock(24); // Get the APE info - d->channels = header.mid(18, 2).toShort(false); - d->sampleRate = header.mid(20, 4).toUInt(false); - d->bitsPerSample = header.mid(16, 2).toShort(false); + d->channels = header.toShort(18, false); + d->sampleRate = header.toUInt(20, false); + d->bitsPerSample = header.toShort(16, false); //d->compressionLevel = - uint totalFrames = header.mid(12, 4).toUInt(false); - uint blocksPerFrame = header.mid(4, 4).toUInt(false); - uint finalFrameBlocks = header.mid(8, 4).toUInt(false); + const uint totalFrames = header.toUInt(12, false); + const uint blocksPerFrame = header.toUInt(4, false); + const uint finalFrameBlocks = header.toUInt(8, false); d->sampleFrames = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; @@ -207,13 +207,13 @@ void APE::Properties::analyzeCurrent() void APE::Properties::analyzeOld() { ByteVector header = d->file->readBlock(26); - uint totalFrames = header.mid(18, 4).toUInt(false); + const uint totalFrames = header.toUInt(18, false); // Fail on 0 length APE files (catches non-finalized APE files) if(totalFrames == 0) return; - short compressionLevel = header.mid(0, 2).toShort(false); + const short compressionLevel = header.toShort(0, false); uint blocksPerFrame; if(d->version >= 3950) blocksPerFrame = 73728 * 4; @@ -221,10 +221,11 @@ void APE::Properties::analyzeOld() blocksPerFrame = 73728; else blocksPerFrame = 9216; - d->channels = header.mid(4, 2).toShort(false); - d->sampleRate = header.mid(6, 4).toUInt(false); - uint finalFrameBlocks = header.mid(22, 4).toUInt(false); - uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; + d->channels = header.toShort(4, false); + d->sampleRate = header.toUInt(6, false); + const uint finalFrameBlocks = header.toUInt(22, false); + const uint totalBlocks + = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; d->length = totalBlocks / d->sampleRate; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } diff --git a/taglib/asf/asffile.cpp b/taglib/asf/asffile.cpp index eb000924..56e93a76 100644 --- a/taglib/asf/asffile.cpp +++ b/taglib/asf/asffile.cpp @@ -187,7 +187,8 @@ ByteVector ASF::File::FilePropertiesObject::guid() void ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size) { BaseObject::parse(file, size); - file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L)); + file->d->properties->setLength( + (int)(data.toLongLong(40, false) / 10000000L - data.toLongLong(56, false) / 1000L)); } ByteVector ASF::File::StreamPropertiesObject::guid() @@ -198,9 +199,9 @@ ByteVector ASF::File::StreamPropertiesObject::guid() void ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size) { BaseObject::parse(file, size); - file->d->properties->setChannels(data.mid(56, 2).toShort(false)); - file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false)); - file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000); + file->d->properties->setChannels(data.toShort(56, false)); + file->d->properties->setSampleRate(data.toUInt(58, false)); + file->d->properties->setBitrate(data.toUInt(62, false) * 8 / 1000); } ByteVector ASF::File::ContentDescriptionObject::guid() diff --git a/taglib/asf/asfpicture.cpp b/taglib/asf/asfpicture.cpp index c36ffa3a..35e52a7d 100644 --- a/taglib/asf/asfpicture.cpp +++ b/taglib/asf/asfpicture.cpp @@ -149,7 +149,7 @@ void ASF::Picture::parse(const ByteVector& bytes) return; int pos = 0; d->type = (Type)bytes[0]; ++pos; - uint dataLen = bytes.mid(pos, 4).toUInt(false); pos+=4; + const uint dataLen = bytes.toUInt(pos, false); pos+=4; const ByteVector nullStringTerminator(2, 0); diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index 972fe728..9f6251cf 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -399,7 +399,7 @@ void FLAC::File::scan() char blockType = header[0] & 0x7f; bool isLastBlock = (header[0] & 0x80) != 0; - uint length = header.mid(1, 3).toUInt(); + uint length = header.toUInt(1U, 3U); // First block should be the stream_info metadata @@ -419,7 +419,7 @@ void FLAC::File::scan() header = readBlock(4); blockType = header[0] & 0x7f; isLastBlock = (header[0] & 0x80) != 0; - length = header.mid(1, 3).toUInt(); + length = header.toUInt(1U, 3U); ByteVector data = readBlock(length); if(data.size() != length || length == 0) { diff --git a/taglib/flac/flacpicture.cpp b/taglib/flac/flacpicture.cpp index 36019248..95eeb6ab 100644 --- a/taglib/flac/flacpicture.cpp +++ b/taglib/flac/flacpicture.cpp @@ -82,10 +82,10 @@ bool FLAC::Picture::parse(const ByteVector &data) return false; } - int pos = 0; - d->type = FLAC::Picture::Type(data.mid(pos, 4).toUInt()); + uint pos = 0; + d->type = FLAC::Picture::Type(data.toUInt(pos)); pos += 4; - uint mimeTypeLength = data.mid(pos, 4).toUInt(); + uint mimeTypeLength = data.toUInt(pos); pos += 4; if(pos + mimeTypeLength + 24 > data.size()) { debug("Invalid picture block."); @@ -93,7 +93,7 @@ bool FLAC::Picture::parse(const ByteVector &data) } d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8); pos += mimeTypeLength; - uint descriptionLength = data.mid(pos, 4).toUInt(); + uint descriptionLength = data.toUInt(pos); pos += 4; if(pos + descriptionLength + 20 > data.size()) { debug("Invalid picture block."); @@ -101,15 +101,15 @@ bool FLAC::Picture::parse(const ByteVector &data) } d->description = String(data.mid(pos, descriptionLength), String::UTF8); pos += descriptionLength; - d->width = data.mid(pos, 4).toUInt(); + d->width = data.toUInt(pos); pos += 4; - d->height = data.mid(pos, 4).toUInt(); + d->height = data.toUInt(pos); pos += 4; - d->colorDepth = data.mid(pos, 4).toUInt(); + d->colorDepth = data.toUInt(pos); pos += 4; - d->numColors = data.mid(pos, 4).toUInt(); + d->numColors = data.toUInt(pos); pos += 4; - uint dataLength = data.mid(pos, 4).toUInt(); + uint dataLength = data.toUInt(pos); pos += 4; if(pos + dataLength > data.size()) { debug("Invalid picture block."); diff --git a/taglib/flac/flacproperties.cpp b/taglib/flac/flacproperties.cpp index 8bdc5d8d..e591193e 100644 --- a/taglib/flac/flacproperties.cpp +++ b/taglib/flac/flacproperties.cpp @@ -124,7 +124,7 @@ void FLAC::Properties::read() return; } - int pos = 0; + uint pos = 0; // Minimum block size (in samples) pos += 2; @@ -138,7 +138,7 @@ void FLAC::Properties::read() // Maximum frame size (in bytes) pos += 3; - uint flags = d->data.mid(pos, 4).toUInt(true); + uint flags = d->data.toUInt(pos, true); pos += 4; d->sampleRate = flags >> 12; @@ -149,7 +149,7 @@ void FLAC::Properties::read() // stream length in samples. (Audio files measured in days) unsigned long long hi = flags & 0xf; - unsigned long long lo = d->data.mid(pos, 4).toUInt(true); + unsigned long long lo = d->data.toUInt(pos, true); pos += 4; d->sampleFrames = (hi << 32) | lo; diff --git a/taglib/mp4/mp4atom.cpp b/taglib/mp4/mp4atom.cpp index 1681ec80..fac593b1 100644 --- a/taglib/mp4/mp4atom.cpp +++ b/taglib/mp4/mp4atom.cpp @@ -52,10 +52,10 @@ MP4::Atom::Atom(File *file) return; } - length = header.mid(0, 4).toUInt(); + length = header.toUInt(); if (length == 1) { - long long longLength = file->readBlock(8).toLongLong(); + const long long longLength = file->readBlock(8).toLongLong(); if (longLength >= 8 && longLength <= 0xFFFFFFFF) { // The atom has a 64-bit length, but it's actually a 32-bit value length = (long)longLength; diff --git a/taglib/mp4/mp4properties.cpp b/taglib/mp4/mp4properties.cpp index d2d04167..e4e95072 100644 --- a/taglib/mp4/mp4properties.cpp +++ b/taglib/mp4/mp4properties.cpp @@ -96,8 +96,8 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } - long long unit = data.mid(28, 8).toLongLong(); - long long length = data.mid(36, 8).toLongLong(); + const long long unit = data.toLongLong(28U); + const long long length = data.toLongLong(36U); d->length = unit ? int(length / unit) : 0; } else { @@ -105,8 +105,8 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } - unsigned int unit = data.mid(20, 4).toUInt(); - unsigned int length = data.mid(24, 4).toUInt(); + const unsigned int unit = data.toUInt(20U); + const unsigned int length = data.toUInt(24U); d->length = unit ? length / unit : 0; } @@ -118,11 +118,11 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) file->seek(atom->offset); data = file->readBlock(atom->length); if(data.mid(20, 4) == "mp4a") { - d->channels = data.mid(40, 2).toShort(); - d->bitsPerSample = data.mid(42, 2).toShort(); - d->sampleRate = data.mid(46, 4).toUInt(); + d->channels = data.toShort(40U); + d->bitsPerSample = data.toShort(42U); + d->sampleRate = data.toUInt(46U); if(data.mid(56, 4) == "esds" && data[64] == 0x03) { - long pos = 65; + uint pos = 65; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } @@ -133,16 +133,16 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) pos += 3; } pos += 10; - d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000; + d->bitrate = (data.toUInt(pos) + 500) / 1000; } } } else if (data.mid(20, 4) == "alac") { if (atom->length == 88 && data.mid(56, 4) == "alac") { d->bitsPerSample = data.at(69); - d->channels = data.at(73); - d->bitrate = data.mid(80, 4).toUInt() / 1000; - d->sampleRate = data.mid(84, 4).toUInt(); + d->channels = data.at(73); + d->bitrate = data.toUInt(80U) / 1000; + d->sampleRate = data.toUInt(84U); } } diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index 3deb84b3..df83796d 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -114,9 +114,9 @@ MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, boo int i = 0; unsigned int pos = 0; while(pos < data.size()) { - int length = data.mid(pos, 4).toUInt(); + const int length = static_cast(data.toUInt(pos)); ByteVector name = data.mid(pos + 4, 4); - int flags = data.mid(pos + 8, 4).toUInt(); + const int flags = static_cast(data.toUInt(pos + 8)); if(freeForm && i < 2) { if(i == 0 && name != "mean") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); @@ -207,8 +207,8 @@ MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - int a = data[0].mid(2, 2).toShort(); - int b = data[0].mid(4, 2).toShort(); + const int a = data[0].toShort(2U); + const int b = data[0].toShort(4U); addItem(atom->name, MP4::Item(a, b)); } } @@ -277,9 +277,9 @@ MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) ByteVector data = file->readBlock(atom->length - 8); unsigned int pos = 0; while(pos < data.size()) { - int length = data.mid(pos, 4).toUInt(); + const int length = static_cast(data.toUInt(pos)); ByteVector name = data.mid(pos + 4, 4); - int flags = data.mid(pos + 8, 4).toUInt(); + const int flags = static_cast(data.toUInt(pos + 8)); if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); break; @@ -530,11 +530,11 @@ MP4::Tag::updateOffsets(long delta, long offset) } d->file->seek(atom->offset + 12); ByteVector data = d->file->readBlock(atom->length - 12); - unsigned int count = data.mid(0, 4).toUInt(); + unsigned int count = data.toUInt(); d->file->seek(atom->offset + 16); - int pos = 4; + uint pos = 4; while(count--) { - long o = data.mid(pos, 4).toUInt(); + long o = static_cast(data.toUInt(pos)); if(o > offset) { o += delta; } @@ -551,11 +551,11 @@ MP4::Tag::updateOffsets(long delta, long offset) } d->file->seek(atom->offset + 12); ByteVector data = d->file->readBlock(atom->length - 12); - unsigned int count = data.mid(0, 4).toUInt(); + unsigned int count = data.toUInt(); d->file->seek(atom->offset + 16); - int pos = 4; + uint pos = 4; while(count--) { - long long o = data.mid(pos, 8).toLongLong(); + long long o = data.toLongLong(pos); if(o > offset) { o += delta; } @@ -575,9 +575,9 @@ MP4::Tag::updateOffsets(long delta, long offset) } d->file->seek(atom->offset + 9); ByteVector data = d->file->readBlock(atom->length - 9); - unsigned int flags = (ByteVector(1, '\0') + data.mid(0, 3)).toUInt(); + const unsigned int flags = data.toUInt(0, 3, true); if(flags & 1) { - long long o = data.mid(7, 8).toLongLong(); + long long o = data.toLongLong(7U); if(o > offset) { o += delta; } diff --git a/taglib/mpc/mpcproperties.cpp b/taglib/mpc/mpcproperties.cpp index 23d41987..d406f8d7 100644 --- a/taglib/mpc/mpcproperties.cpp +++ b/taglib/mpc/mpcproperties.cpp @@ -207,7 +207,7 @@ void MPC::Properties::readSV8(File *file) d->sampleFrames = readSize(data.mid(pos), pos); ulong begSilence = readSize(data.mid(pos), pos); - std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(pos, 2).toUShort(true))); + std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(data.toUShort(pos, true))); pos += 2; d->sampleRate = sftable[flags[15] * 4 + flags[14] * 2 + flags[13]]; @@ -228,10 +228,10 @@ void MPC::Properties::readSV8(File *file) int replayGainVersion = data[0]; if(replayGainVersion == 1) { - d->trackGain = data.mid(1, 2).toUInt(true); - d->trackPeak = data.mid(3, 2).toUInt(true); - d->albumGain = data.mid(5, 2).toUInt(true); - d->albumPeak = data.mid(7, 2).toUInt(true); + d->trackGain = data.toShort(1, true); + d->trackPeak = data.toShort(3, true); + d->albumGain = data.toShort(5, true); + d->albumPeak = data.toShort(7, true); } } @@ -252,18 +252,18 @@ void MPC::Properties::readSV7(const ByteVector &data) if(d->version < 7) return; - d->totalFrames = data.mid(4, 4).toUInt(false); + d->totalFrames = data.toUInt(4, false); - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(8, 4).toUInt(false))); + std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(8, false))); d->sampleRate = sftable[flags[17] * 2 + flags[16]]; d->channels = 2; - uint gapless = data.mid(5, 4).toUInt(false); + uint gapless = data.toUInt(5, false); - d->trackGain = data.mid(14,2).toShort(false); - d->trackPeak = data.mid(12,2).toUInt(false); - d->albumGain = data.mid(18,2).toShort(false); - d->albumPeak = data.mid(16,2).toUInt(false); + d->trackGain = data.toShort(14, false); + d->trackPeak = data.toShort(12, false); + d->albumGain = data.toShort(18, false); + d->albumPeak = data.toShort(16, false); // convert gain info if(d->trackGain != 0) { @@ -293,7 +293,7 @@ void MPC::Properties::readSV7(const ByteVector &data) d->sampleFrames = d->totalFrames * 1152 - 576; } else { - uint headerData = data.mid(0, 4).toUInt(false); + uint headerData = data.toUInt(0, false); d->bitrate = (headerData >> 23) & 0x01ff; d->version = (headerData >> 11) & 0x03ff; @@ -301,9 +301,9 @@ void MPC::Properties::readSV7(const ByteVector &data) d->channels = 2; if(d->version >= 5) - d->totalFrames = data.mid(4, 4).toUInt(false); + d->totalFrames = data.toUInt(4, false); else - d->totalFrames = data.mid(6, 2).toUInt(false); + d->totalFrames = data.toUShort(6, false); d->sampleFrames = d->totalFrames * 1152 - 576; } diff --git a/taglib/mpeg/id3v2/frames/popularimeterframe.cpp b/taglib/mpeg/id3v2/frames/popularimeterframe.cpp index cfe8c9f4..3d4429f7 100644 --- a/taglib/mpeg/id3v2/frames/popularimeterframe.cpp +++ b/taglib/mpeg/id3v2/frames/popularimeterframe.cpp @@ -109,7 +109,7 @@ void PopularimeterFrame::parseFields(const ByteVector &data) if(pos < size) { d->rating = (unsigned char)(data[pos++]); if(pos < size) { - d->counter = data.mid(pos, 4).toUInt(); + d->counter = data.toUInt(static_cast(pos)); } } } diff --git a/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp b/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp index 955b3ad0..e3efbc38 100644 --- a/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp +++ b/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp @@ -191,7 +191,7 @@ void RelativeVolumeFrame::parseFields(const ByteVector &data) ChannelData &channel = d->channels[type]; - channel.volumeAdjustment = data.mid(pos, 2).toShort(); + channel.volumeAdjustment = data.toShort(static_cast(pos)); pos += 2; channel.peakVolume.bitsRepresentingPeak = data[pos]; diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index ddf6c5b5..c5c5585d 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -642,7 +642,7 @@ void Frame::Header::setData(const ByteVector &data, uint version) return; } - d->frameSize = data.mid(3, 3).toUInt(); + d->frameSize = data.toUInt(3, 3, true); break; } @@ -670,7 +670,7 @@ void Frame::Header::setData(const ByteVector &data, uint version) // Set the size -- the frame size is the four bytes starting at byte four in // the frame header (structure 4) - d->frameSize = data.mid(4, 4).toUInt(); + d->frameSize = data.toUInt(4U); { // read the first byte of flags std::bitset<8> flags(data[8]); @@ -717,7 +717,7 @@ void Frame::Header::setData(const ByteVector &data, uint version) // iTunes writes v2.4 tags with v2.3-like frame sizes if(d->frameSize > 127) { if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) { - unsigned int uintSize = data.mid(4, 4).toUInt(); + unsigned int uintSize = data.toUInt(4U); if(isValidFrameID(data.mid(uintSize + 10, 4))) { d->frameSize = uintSize; } diff --git a/taglib/mpeg/id3v2/id3v2synchdata.cpp b/taglib/mpeg/id3v2/id3v2synchdata.cpp index d4bab679..60698d3c 100644 --- a/taglib/mpeg/id3v2/id3v2synchdata.cpp +++ b/taglib/mpeg/id3v2/id3v2synchdata.cpp @@ -49,7 +49,7 @@ TagLib::uint SynchData::toUInt(const ByteVector &data) // Invalid data; assume this was created by some buggy software that just // put normal integers here rather than syncsafe ones, and try it that // way. - sum = (data.size() > 4) ? data.mid(0, 4).toUInt() : data.toUInt(); + sum = data.toUInt(); } return sum; diff --git a/taglib/mpeg/xingheader.cpp b/taglib/mpeg/xingheader.cpp index 1ba932de..9e20127e 100644 --- a/taglib/mpeg/xingheader.cpp +++ b/taglib/mpeg/xingheader.cpp @@ -108,8 +108,8 @@ void MPEG::XingHeader::parse(const ByteVector &data) return; } - d->frames = data.mid(8, 4).toUInt(); - d->size = data.mid(12, 4).toUInt(); + d->frames = data.toUInt(8U); + d->size = data.toUInt(12U); d->valid = true; } diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index 510c01f8..18506b2e 100644 --- a/taglib/ogg/flac/oggflacfile.cpp +++ b/taglib/ogg/flac/oggflacfile.cpp @@ -241,7 +241,7 @@ void Ogg::FLAC::File::scan() char blockType = header[0] & 0x7f; bool lastBlock = (header[0] & 0x80) != 0; - uint length = header.mid(1, 3).toUInt(); + uint length = header.toUInt(1, 3, true); overhead += length; // Sanity: First block should be the stream_info metadata @@ -251,7 +251,7 @@ void Ogg::FLAC::File::scan() return; } - d->streamInfoData = metadataHeader.mid(4,length); + d->streamInfoData = metadataHeader.mid(4, length); // Search through the remaining metadata @@ -264,7 +264,7 @@ void Ogg::FLAC::File::scan() header = metadataHeader.mid(0, 4); blockType = header[0] & 0x7f; lastBlock = (header[0] & 0x80) != 0; - length = header.mid(1, 3).toUInt(); + length = header.toUInt(1, 3, true); overhead += length; if(blockType == 1) { diff --git a/taglib/ogg/oggpageheader.cpp b/taglib/ogg/oggpageheader.cpp index f9608ab7..b9333135 100644 --- a/taglib/ogg/oggpageheader.cpp +++ b/taglib/ogg/oggpageheader.cpp @@ -255,9 +255,9 @@ void Ogg::PageHeader::read() d->firstPageOfStream = flags.test(1); d->lastPageOfStream = flags.test(2); - d->absoluteGranularPosition = data.mid(6, 8).toLongLong(false); - d->streamSerialNumber = data.mid(14, 4).toUInt(false); - d->pageSequenceNumber = data.mid(18, 4).toUInt(false); + d->absoluteGranularPosition = data.toLongLong(6, false); + d->streamSerialNumber = data.toUInt(14, false); + d->pageSequenceNumber = data.toUInt(18, false); // Byte number 27 is the number of page segments, which is the only variable // length portion of the page header. After reading the number of page diff --git a/taglib/ogg/opus/opusproperties.cpp b/taglib/ogg/opus/opusproperties.cpp index 70679d4c..7bdcd39d 100644 --- a/taglib/ogg/opus/opusproperties.cpp +++ b/taglib/ogg/opus/opusproperties.cpp @@ -118,7 +118,7 @@ void Opus::Properties::read() ByteVector data = d->file->packet(0); // *Magic Signature* - int pos = 8; + uint pos = 8; // *Version* (8 bits, unsigned) d->opusVersion = uchar(data.at(pos)); @@ -129,11 +129,11 @@ void Opus::Properties::read() pos += 1; // *Pre-skip* (16 bits, unsigned, little endian) - ushort preSkip = data.mid(pos, 2).toUShort(false); + const ushort preSkip = data.toUShort(pos, false); pos += 2; // *Input Sample Rate* (32 bits, unsigned, little endian) - d->inputSampleRate = data.mid(pos, 4).toUInt(false); + d->inputSampleRate = data.toUInt(pos, false); pos += 4; // *Output Gain* (16 bits, signed, little endian) diff --git a/taglib/ogg/speex/speexproperties.cpp b/taglib/ogg/speex/speexproperties.cpp index 980f12df..5aaa9153 100644 --- a/taglib/ogg/speex/speexproperties.cpp +++ b/taglib/ogg/speex/speexproperties.cpp @@ -113,32 +113,32 @@ void Speex::Properties::read() ByteVector data = d->file->packet(0); - int pos = 28; + uint pos = 28; // speex_version_id; /**< Version for Speex (for checking compatibility) */ - d->speexVersion = data.mid(pos, 4).toUInt(false); + d->speexVersion = data.toUInt(pos, false); pos += 4; // header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */ pos += 4; // rate; /**< Sampling rate used */ - d->sampleRate = data.mid(pos, 4).toUInt(false); + d->sampleRate = data.toUInt(pos, false); pos += 4; // mode; /**< Mode used (0 for narrowband, 1 for wideband) */ - d->mode = data.mid(pos, 4).toUInt(false); + d->mode = data.toUInt(pos, false); pos += 4; // mode_bitstream_version; /**< Version ID of the bit-stream */ pos += 4; // nb_channels; /**< Number of channels encoded */ - d->channels = data.mid(pos, 4).toUInt(false); + d->channels = data.toUInt(pos, false); pos += 4; // bitrate; /**< Bit-rate used */ - d->bitrate = data.mid(pos, 4).toUInt(false); + d->bitrate = data.toUInt(pos, false); pos += 4; // frame_size; /**< Size of frames */ @@ -146,7 +146,7 @@ void Speex::Properties::read() pos += 4; // vbr; /**< 1 for a VBR encoding, 0 otherwise */ - d->vbr = data.mid(pos, 4).toUInt(false) == 1; + d->vbr = data.toUInt(pos, false) == 1; pos += 4; // frames_per_packet; /**< Number of frames stored per Ogg packet */ diff --git a/taglib/ogg/vorbis/vorbisproperties.cpp b/taglib/ogg/vorbis/vorbisproperties.cpp index c67e1677..b5e88bfd 100644 --- a/taglib/ogg/vorbis/vorbisproperties.cpp +++ b/taglib/ogg/vorbis/vorbisproperties.cpp @@ -133,7 +133,7 @@ void Vorbis::Properties::read() ByteVector data = d->file->packet(0); - int pos = 0; + uint pos = 0; if(data.mid(pos, 7) != vorbisSetupHeaderID) { debug("Vorbis::Properties::read() -- invalid Vorbis identification header"); @@ -142,22 +142,22 @@ void Vorbis::Properties::read() pos += 7; - d->vorbisVersion = data.mid(pos, 4).toUInt(false); + d->vorbisVersion = data.toUInt(pos, false); pos += 4; d->channels = uchar(data[pos]); pos += 1; - d->sampleRate = data.mid(pos, 4).toUInt(false); + d->sampleRate = data.toUInt(pos, false); pos += 4; - d->bitrateMaximum = data.mid(pos, 4).toUInt(false); + d->bitrateMaximum = data.toUInt(pos, false); pos += 4; - d->bitrateNominal = data.mid(pos, 4).toUInt(false); + d->bitrateNominal = data.toUInt(pos, false); pos += 4; - d->bitrateMinimum = data.mid(pos, 4).toUInt(false); + d->bitrateMinimum = data.toUInt(pos, false); // TODO: Later this should be only the "fast" mode. d->bitrate = d->bitrateNominal; diff --git a/taglib/ogg/xiphcomment.cpp b/taglib/ogg/xiphcomment.cpp index 675614b3..51c2f9f0 100644 --- a/taglib/ogg/xiphcomment.cpp +++ b/taglib/ogg/xiphcomment.cpp @@ -340,7 +340,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) uint pos = 0; - uint vendorLength = data.mid(0, 4).toUInt(false); + const uint vendorLength = data.toUInt(0, false); pos += 4; d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); @@ -348,7 +348,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) // Next the number of fields in the comment vector. - uint commentFields = data.mid(pos, 4).toUInt(false); + const uint commentFields = data.toUInt(pos, false); pos += 4; if(commentFields > (data.size() - 8) / 4) { @@ -360,7 +360,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) // Each comment field is in the format "KEY=value" in a UTF8 string and has // 4 bytes before the text starts that gives the length. - uint commentLength = data.mid(pos, 4).toUInt(false); + const uint commentLength = data.toUInt(pos, false); pos += 4; String comment = String(data.mid(pos, commentLength), String::UTF8); diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index 3ea27582..1ed03d6b 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -150,9 +150,9 @@ TagLib::uint RIFF::AIFF::Properties::sampleFrames() const void RIFF::AIFF::Properties::read(const ByteVector &data) { - d->channels = data.mid(0, 2).toShort(); - d->sampleFrames = data.mid(2, 4).toUInt(); - d->sampleWidth = data.mid(6, 2).toShort(); + d->channels = data.toShort(0U); + d->sampleFrames = data.toUInt(2U); + d->sampleWidth = data.toShort(6U); double sampleRate = ConvertFromIeeeExtended(reinterpret_cast(data.mid(8, 10).data())); d->sampleRate = (int)sampleRate; d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0); diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index df1d2f81..5ce1df90 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -249,7 +249,7 @@ void RIFF::Info::Tag::parse(const ByteVector &data) { uint p = 4; while(p < data.size()) { - uint size = data.mid(p + 4, 4).toUInt(false); + const uint size = data.toUInt(p + 4, false); d->fieldListMap[data.mid(p, 4)] = TagPrivate::stringHandler->parse(data.mid(p + 8, size)); p += ((size + 1) & ~1) + 8; diff --git a/taglib/riff/wav/wavproperties.cpp b/taglib/riff/wav/wavproperties.cpp index 9e7ea70c..8062df5f 100644 --- a/taglib/riff/wav/wavproperties.cpp +++ b/taglib/riff/wav/wavproperties.cpp @@ -115,12 +115,12 @@ TagLib::uint RIFF::WAV::Properties::sampleFrames() const void RIFF::WAV::Properties::read(const ByteVector &data) { - d->format = data.mid(0, 2).toShort(false); - d->channels = data.mid(2, 2).toShort(false); - d->sampleRate = data.mid(4, 4).toUInt(false); - d->sampleWidth = data.mid(14, 2).toShort(false); + d->format = data.toShort(0, false); + d->channels = data.toShort(2, false); + d->sampleRate = data.toUInt(4, false); + d->sampleWidth = data.toShort(14, false); - uint byteRate = data.mid(8, 4).toUInt(false); + const uint byteRate = data.toUInt(8, false); d->bitrate = byteRate * 8 / 1000; d->length = byteRate > 0 ? d->streamLength / byteRate : 0; diff --git a/taglib/toolkit/tbyteswap.cpp b/taglib/toolkit/tbyteswap.cpp index 714033e8..cee2772d 100644 --- a/taglib/toolkit/tbyteswap.cpp +++ b/taglib/toolkit/tbyteswap.cpp @@ -191,7 +191,7 @@ namespace TagLib #else - const bool isLittleEndianSystem = isLittleEndianSystem(); + const bool isLittleEndianSystem = isLittleEndian(); #endif } diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index ca65cfaa..e6e8cb85 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -24,9 +24,10 @@ ***************************************************************************/ #include +#include +#include #include #include -#include #include "tbytevector.h" #include "tbyteswap.h" @@ -201,24 +202,35 @@ ulonglong byteSwap(ulonglong x) } template -T toNumber(const ByteVector &v, bool mostSignificantByteFirst) +T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) { - if(v.isEmpty()) { - debug("toNumber() -- data is empty, returning 0"); + if(offset + sizeof(T) > v.size()) { + debug("toNumber() -- offset is out of range. Returning 0."); return 0; } - if(v.size() >= sizeof(T)) { - if(isLittleEndianSystem == mostSignificantByteFirst) - return byteSwap(*reinterpret_cast(v.data())); - else - return *reinterpret_cast(v.data()); + if(isLittleEndianSystem == mostSignificantByteFirst) + return byteSwap(*reinterpret_cast(v.data() + offset)); + else + return *reinterpret_cast(v.data() + offset); +} + +template +T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignificantByteFirst) +{ + if(offset + length > v.size()) { + debug("toNumber() -- offset and/or length is out of range. Returning 0."); + return 0; + } + + if(length >= sizeof(T)) { + return toNumber(v, offset, mostSignificantByteFirst); } else { T sum = 0; - for(size_t i = 0; i < v.size(); i++) { - const size_t shift = (mostSignificantByteFirst ? v.size() - 1 - i : i) * 8; - sum |= static_cast(static_cast(v[i]) << shift); + 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); } return sum; @@ -441,11 +453,8 @@ const char *ByteVector::data() const ByteVector ByteVector::mid(uint index, uint length) const { - if(index > size()) - index = size(); - - if(length > size() - index) - length = size() - index; + index = std::min(index, size()); + length = std::min(length, size() - index); return ByteVector(*this, index, length); } @@ -687,22 +696,47 @@ TagLib::uint ByteVector::checksum() const TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, 0, mostSignificantByteFirst); +} + +TagLib::uint ByteVector::toUInt(uint offset, bool mostSignificantByteFirst) const +{ + return toNumber(*this, offset, mostSignificantByteFirst); +} + +TagLib::uint ByteVector::toUInt(uint offset, uint length, bool mostSignificantByteFirst) const +{ + return toNumber(*this, offset, length, mostSignificantByteFirst); } short ByteVector::toShort(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, 0, mostSignificantByteFirst); +} + +short ByteVector::toShort(uint offset, bool mostSignificantByteFirst) const +{ + return toNumber(*this, offset, mostSignificantByteFirst); } unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, 0, mostSignificantByteFirst); +} + +unsigned short ByteVector::toUShort(uint offset, bool mostSignificantByteFirst) const +{ + return toNumber(*this, offset, mostSignificantByteFirst); } long long ByteVector::toLongLong(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, 0, mostSignificantByteFirst); +} + +long long ByteVector::toLongLong(uint offset, bool mostSignificantByteFirst) const +{ + return toNumber(*this, offset, mostSignificantByteFirst); } const char &ByteVector::operator[](int index) const diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index ca810130..4a0f2b91 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -291,7 +291,32 @@ namespace TagLib { uint toUInt(bool mostSignificantByteFirst = true) const; /*! - * Converts the first 2 bytes of the vector to a short. + * Converts the 4 bytes at \a offset of the vector to an unsigned integer. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == + * 0x01000000 == 1. + * + * \see fromUInt() + */ + uint toUInt(uint offset, bool mostSignificantByteFirst = true) const; + + /*! + * Converts the \a length bytes at \a offset of the vector to an unsigned + * integer. If \a length is larger than 4, the excess is ignored. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == + * 0x01000000 == 1. + * + * \see fromUInt() + */ + uint toUInt(uint offset, uint length, bool mostSignificantByteFirst = true) const; + + /*! + * Converts the first 2 bytes of the vector to a (signed) short. * * If \a mostSignificantByteFirst is true this will operate left to right * evaluating the integer. For example if \a mostSignificantByteFirst is @@ -301,6 +326,17 @@ namespace TagLib { */ short toShort(bool mostSignificantByteFirst = true) const; + /*! + * Converts the 2 bytes at \a offset of the vector to a (signed) short. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. + * + * \see fromShort() + */ + short toShort(uint offset, bool mostSignificantByteFirst = true) const; + /*! * Converts the first 2 bytes of the vector to a unsigned short. * @@ -312,6 +348,17 @@ namespace TagLib { */ unsigned short toUShort(bool mostSignificantByteFirst = true) const; + /*! + * Converts the 2 bytes at \a offset of the vector to a unsigned short. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. + * + * \see fromShort() + */ + unsigned short toUShort(uint offset, bool mostSignificantByteFirst = true) const; + /*! * Converts the first 8 bytes of the vector to a (signed) long long. * @@ -324,6 +371,18 @@ namespace TagLib { */ long long toLongLong(bool mostSignificantByteFirst = true) const; + /*! + * Converts the 8 bytes at \a offset of the vector to a (signed) long long. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1, + * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. + * + * \see fromUInt() + */ + long long toLongLong(uint offset, bool mostSignificantByteFirst = true) const; + /*! * Creates a 4 byte ByteVector based on \a value. If * \a mostSignificantByteFirst is true, then this will operate left to right diff --git a/taglib/trueaudio/trueaudioproperties.cpp b/taglib/trueaudio/trueaudioproperties.cpp index 9b251ff1..dedd74e9 100644 --- a/taglib/trueaudio/trueaudioproperties.cpp +++ b/taglib/trueaudio/trueaudioproperties.cpp @@ -133,16 +133,16 @@ void TrueAudio::Properties::read() // Skip the audio format pos += 2; - d->channels = d->data.mid(pos, 2).toShort(false); + d->channels = d->data.toShort(pos, false); pos += 2; - d->bitsPerSample = d->data.mid(pos, 2).toShort(false); + d->bitsPerSample = d->data.toShort(pos, false); pos += 2; - d->sampleRate = d->data.mid(pos, 4).toUInt(false); + d->sampleRate = d->data.toUInt(pos, false); pos += 4; - d->sampleFrames = d->data.mid(pos, 4).toUInt(false); + d->sampleFrames = d->data.toUInt(pos, false); d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; diff --git a/taglib/wavpack/wavpackproperties.cpp b/taglib/wavpack/wavpackproperties.cpp index 1715f425..3f791544 100644 --- a/taglib/wavpack/wavpackproperties.cpp +++ b/taglib/wavpack/wavpackproperties.cpp @@ -148,17 +148,17 @@ void WavPack::Properties::read() if(!d->data.startsWith("wvpk")) return; - d->version = d->data.mid(8, 2).toShort(false); + d->version = d->data.toShort(8, false); if(d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS) return; - unsigned int flags = d->data.mid(24, 4).toUInt(false); + const unsigned int flags = d->data.toUInt(24, false); d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - ((flags & SHIFT_MASK) >> SHIFT_LSB); d->sampleRate = sample_rates[(flags & SRATE_MASK) >> SRATE_LSB]; d->channels = (flags & MONO_FLAG) ? 1 : 2; - unsigned int samples = d->data.mid(12, 4).toUInt(false); + unsigned int samples = d->data.toUInt(12, false); if(samples == ~0u) { if(d->file && d->style != Fast) { samples = seekFinalIndex(); @@ -186,14 +186,14 @@ unsigned int WavPack::Properties::seekFinalIndex() ByteVector data = d->file->readBlock(32); if(data.size() != 32) return 0; - int version = data.mid(8, 2).toShort(false); + const int version = data.toShort(8, false); if(version < MIN_STREAM_VERS || version > MAX_STREAM_VERS) continue; - unsigned int flags = data.mid(24, 4).toUInt(false); + const unsigned int flags = data.toUInt(24, false); if(!(flags & FINAL_BLOCK)) return 0; - unsigned int blockIndex = data.mid(16, 4).toUInt(false); - unsigned int blockSamples = data.mid(20, 4).toUInt(false); + const unsigned int blockIndex = data.toUInt(16, false); + const unsigned int blockSamples = data.toUInt(20, false); return blockIndex + blockSamples; } From a71749a6b57d1db3cee871df664105478504e3ba Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Thu, 18 Apr 2013 19:52:52 +0900 Subject: [PATCH 14/33] Fix some GCC specific warnings --- taglib/toolkit/tfilestream.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index 52252023..da9311e3 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -369,6 +369,9 @@ void FileStream::seek(long offset, Position p) case End: whence = FILE_END; break; + default: + debug("FileStream::seek() -- Invalid Position value."); + return; } SetFilePointer(d->file, offset, NULL, whence); @@ -386,6 +389,9 @@ void FileStream::seek(long offset, Position p) case End: whence = SEEK_END; break; + default: + debug("FileStream::seek() -- Invalid Position value."); + return; } fseek(d->file, offset, whence); @@ -429,10 +435,10 @@ long FileStream::length() if(!d->file) return 0; - long curpos = tell(); + const long curpos = tell(); seek(0, End); - long endpos = tell(); + const long endpos = tell(); seek(curpos, Beginning); @@ -448,7 +454,7 @@ void FileStream::truncate(long length) { #ifdef _WIN32 - long currentPos = tell(); + const long currentPos = tell(); seek(length); SetEndOfFile(d->file); @@ -457,7 +463,10 @@ void FileStream::truncate(long length) #else - ftruncate(fileno(d->file), length); + const int error = ftruncate(fileno(d->file), length); + if(error != 0) { + debug("FileStream::truncate() -- Coundn't truncate the file."); + } #endif } From e0805b039cd186ecd810ccab7a788cacf9d3a065 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Thu, 18 Apr 2013 22:16:59 +0900 Subject: [PATCH 15/33] Fix improper file handling in Win32 --- taglib/toolkit/tfilestream.cpp | 83 +++++++++++++++++++++++----------- taglib/toolkit/tiostream.h | 3 ++ 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index da9311e3..5b7676b2 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -56,9 +56,9 @@ namespace { HANDLE openFile(const FileName &path, bool readOnly) { - DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); + const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); - if(wcslen(path) > 0) + if(!path.wstr().empty()) return CreateFileW(path, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); else return CreateFileA(path, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); @@ -67,17 +67,19 @@ namespace { size_t fread(void *ptr, size_t size, size_t nmemb, HANDLE stream) { DWORD readLen; - ReadFile(stream, ptr, size * nmemb, &readLen, NULL); - - return (readLen / size); + if(ReadFile(stream, ptr, size * nmemb, &readLen, NULL)) + return (readLen / size); + else + return 0; } size_t fwrite(const void *ptr, size_t size, size_t nmemb, HANDLE stream) { DWORD writtenLen; - WriteFile(stream, ptr, size * nmemb, &writtenLen, NULL); - - return writtenLen; + if(WriteFile(stream, ptr, size * nmemb, &writtenLen, NULL)) + return (writtenLen / size); + else + return 0; } #else @@ -103,7 +105,7 @@ namespace { class FileStream::FileStreamPrivate { public: - FileStreamPrivate(FileName fileName, bool openReadOnly); + FileStreamPrivate(const FileName &fileName, bool openReadOnly); #ifdef _WIN32 @@ -122,7 +124,7 @@ public: static const uint bufferSize = 1024; }; -FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName, bool openReadOnly) : +FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool openReadOnly) : file(InvalidFile), name(fileName), readOnly(true), @@ -138,8 +140,22 @@ FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName, bool openRea else file = openFile(name, true); - if(file == InvalidFile) { + if(file == InvalidFile) + { +# ifdef _WIN32 + + if(!name.wstr().empty()) { + debug("Could not open file " + String(name.wstr())); + } + else { + debug("Could not open file " + String(name.str())); + } + +# else + debug("Could not open file " + String((const char *) name)); + +# endif } } @@ -148,20 +164,20 @@ FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName, bool openRea //////////////////////////////////////////////////////////////////////////////// FileStream::FileStream(FileName file, bool openReadOnly) + : d(new FileStreamPrivate(file, openReadOnly)) { - d = new FileStreamPrivate(file, openReadOnly); } FileStream::~FileStream() { #ifdef _WIN32 - if(d->file) + if(isOpen()) CloseHandle(d->file); #else - if(d->file) + if(isOpen()) fclose(d->file); #endif @@ -176,8 +192,8 @@ FileName FileStream::name() const ByteVector FileStream::readBlock(ulong length) { - if(!d->file) { - debug("FileStream::readBlock() -- Invalid File"); + if(!isOpen()) { + debug("File::readBlock() -- invalid file."); return ByteVector::null; } @@ -198,11 +214,13 @@ ByteVector FileStream::readBlock(ulong length) void FileStream::writeBlock(const ByteVector &data) { - if(!d->file) + if(!isOpen()) { + debug("File::writeBlock() -- invalid file."); return; + } - if(d->readOnly) { - debug("File::writeBlock() -- attempted to write to a file that is not writable"); + if(readOnly()) { + debug("File::writeBlock() -- read only file."); return; } @@ -211,8 +229,15 @@ void FileStream::writeBlock(const ByteVector &data) void FileStream::insert(const ByteVector &data, ulong start, ulong replace) { - if(!d->file) + if(!isOpen()) { + debug("File::insert() -- invalid file."); return; + } + + if(readOnly()) { + debug("File::insert() -- read only file."); + return; + } if(data.size() == replace) { seek(start); @@ -309,8 +334,10 @@ void FileStream::insert(const ByteVector &data, ulong start, ulong replace) void FileStream::removeBlock(ulong start, ulong length) { - if(!d->file) + if(!isOpen()) { + debug("File::removeBlock() -- invalid file."); return; + } ulong bufferLength = bufferSize(); @@ -346,13 +373,13 @@ bool FileStream::readOnly() const bool FileStream::isOpen() const { - return (d->file != NULL); + return (d->file != InvalidFile); } void FileStream::seek(long offset, Position p) { - if(!d->file) { - debug("File::seek() -- trying to seek in a file that isn't opened."); + if(!isOpen()) { + debug("File::seek() -- invalid file."); return; } @@ -427,14 +454,16 @@ long FileStream::tell() const long FileStream::length() { + if(!isOpen()) { + debug("File::length() -- invalid file."); + return 0; + } + // Do some caching in case we do multiple calls. if(d->size > 0) return d->size; - if(!d->file) - return 0; - const long curpos = tell(); seek(0, End); diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index 1508e402..ee43154b 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -39,6 +39,9 @@ namespace TagLib { FileName(const wchar_t *name) : m_wname(name) {} FileName(const char *name) : m_name(name) {} + FileName(const FileName &name) + : m_wname(name.m_wname), m_name(name.m_name) {} + operator const wchar_t *() const { return m_wname.c_str(); } operator const char *() const { return m_name.c_str(); } From d959ab89f171055088917bb94d0ab864258ccf87 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Fri, 19 Apr 2013 06:13:27 +0900 Subject: [PATCH 16/33] Fix an error message in Win32 --- taglib/CMakeLists.txt | 4 ---- taglib/fileref.cpp | 1 - taglib/fileref.h | 4 ++++ taglib/toolkit/tfilestream.cpp | 37 ++++++++++++++++++++++++++++------ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index 63b88bb7..a940caf5 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -311,10 +311,6 @@ if(ZLIB_FOUND) target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() -if(WIN32 AND NOT TAGLIB_STATIC) - target_link_libraries(tag shlwapi.lib) -endif() - set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index a6c96c07..46e59ff1 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -35,7 +35,6 @@ # include #endif - #include #include #include diff --git a/taglib/fileref.h b/taglib/fileref.h index 0f0c21a4..95a7506d 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -32,6 +32,10 @@ #include "taglib_export.h" #include "audioproperties.h" +#if _WIN32 +# pragma comment(lib, "shlwapi.lib") +#endif + namespace TagLib { class Tag; diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index 5b7676b2..c008c190 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -82,6 +82,36 @@ namespace { return 0; } +# if _DEBUG + + // Convert a string in a local encoding into a UTF-16 string. + + // This function should only be used to generate an error message. + // In actual use, file names in local encodings are passed to CreateFileA() + // without any conversions. + + String fileNameToString(const FileName &name) + { + if(!name.wstr().empty()) { + return String(name.wstr()); + } + else if(!name.str().empty()) { + const int len = MultiByteToWideChar(CP_ACP, 0, name.str().c_str(), -1, NULL, 0); + if(len == 0) + return String::null; + + wstring wstr(len, L'\0'); + MultiByteToWideChar(CP_ACP, 0, name.str().c_str(), -1, &wstr[0], len); + + return String(wstr); + } + else { + return String::null; + } + } + +# endif + #else // For non-Windows @@ -144,12 +174,7 @@ FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool { # ifdef _WIN32 - if(!name.wstr().empty()) { - debug("Could not open file " + String(name.wstr())); - } - else { - debug("Could not open file " + String(name.str())); - } + debug("Could not open file " + fileNameToString(name)); # else From e8498b9264c2397ff1a101c9eef7676ca95d6c3c Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Sat, 20 Apr 2013 05:54:06 +0900 Subject: [PATCH 17/33] Fix -Wcast-align violation --- taglib/riff/aiff/aiffproperties.cpp | 4 +-- taglib/toolkit/tbytevector.cpp | 8 ++++-- taglib/toolkit/tstring.cpp | 39 ++++++++++++++++------------- taglib/toolkit/tstring.h | 1 - 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index 1ed03d6b..18b973eb 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -39,7 +39,7 @@ #define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) -static double ConvertFromIeeeExtended(unsigned char *bytes) +static double ConvertFromIeeeExtended(const TagLib::uchar *bytes) { double f; int expon; @@ -153,7 +153,7 @@ void RIFF::AIFF::Properties::read(const ByteVector &data) d->channels = data.toShort(0U); d->sampleFrames = data.toUInt(2U); d->sampleWidth = data.toShort(6U); - double sampleRate = ConvertFromIeeeExtended(reinterpret_cast(data.mid(8, 10).data())); + double sampleRate = ConvertFromIeeeExtended(reinterpret_cast(data.data() + 8)); d->sampleRate = (int)sampleRate; d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0); d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index e6e8cb85..f1ca4c78 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -209,10 +209,14 @@ T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) return 0; } + // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. + T tmp; + ::memcpy(&tmp, v.data() + offset, sizeof(T)); + if(isLittleEndianSystem == mostSignificantByteFirst) - return byteSwap(*reinterpret_cast(v.data() + offset)); + return byteSwap(tmp); else - return *reinterpret_cast(v.data() + offset); + return tmp; } template diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index bb0b0b93..22590c89 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -789,16 +789,32 @@ void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) } } -template -void String::internalCopyFromUTF16(const char *s, size_t length, Type t) +void String::copyFromUTF16(const char *s, size_t length, Type t) { - // Non specialized version. Used where sizeof(wchar_t) != 2. +#if !defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + + // It's certain that sizeof(wchar_t) == 2 and alignment-tolerant. + + copyFromUTF16(reinterpret_cast(s), length / 2, t); + +#else + + // Maybe sizeof(wchar_t) != 2 or alignment-strict. bool swap; if(t == UTF16) { - if(length >= 2 && *reinterpret_cast(s) == 0xfeff) + if(length < 2) { + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; + } + + // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. + ushort bom; + ::memcpy(&bom, s, 2); + + if(bom == 0xfeff) swap = false; // Same as CPU endian. No need to swap bytes. - else if(length >= 2 && *reinterpret_cast(s) == 0xfffe) + else if(bom == 0xfffe) swap = true; // Not same as CPU endian. Need to swap bytes. else { debug("String::copyFromUTF16() - Invalid UTF16 string."); @@ -816,19 +832,8 @@ void String::internalCopyFromUTF16(const char *s, size_t length, Type t) d->data[i] = swap ? combine(*s, *(s + 1)) : combine(*(s + 1), *s); s += 2; } -} -template <> -void String::internalCopyFromUTF16<2>(const char *s, size_t length, Type t) -{ - // Specialized version for where sizeof(wchar_t) == 2. - - copyFromUTF16(reinterpret_cast(s), length / 2, t); -} - -void String::copyFromUTF16(const char *s, size_t length, Type t) -{ - internalCopyFromUTF16(s, length, t); +#endif } const String::Type String::WCharByteOrder = isLittleEndianSystem ? String::UTF16LE : String::UTF16BE; diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index 150d7c37..7811ecf6 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -474,7 +474,6 @@ namespace TagLib { */ void copyFromUTF16(const char *s, size_t length, Type t); - template void internalCopyFromUTF16(const char *s, size_t length, Type t); /*! From 8a7d1dd796dd909c826f8bf1aca0c1402b47f34a Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Sat, 20 Apr 2013 09:28:19 +0900 Subject: [PATCH 18/33] Fix reading corrupted ID3v2 syncdata --- taglib/mpeg/id3v2/id3v2synchdata.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/taglib/mpeg/id3v2/id3v2synchdata.cpp b/taglib/mpeg/id3v2/id3v2synchdata.cpp index 60698d3c..4acfd914 100644 --- a/taglib/mpeg/id3v2/id3v2synchdata.cpp +++ b/taglib/mpeg/id3v2/id3v2synchdata.cpp @@ -49,7 +49,14 @@ TagLib::uint SynchData::toUInt(const ByteVector &data) // Invalid data; assume this was created by some buggy software that just // put normal integers here rather than syncsafe ones, and try it that // way. - sum = data.toUInt(); + if(data.size() >= 4) { + sum = data.toUInt(0, true); + } + else { + ByteVector tmp(data); + tmp.resize(4); + sum = tmp.toUInt(0, true); + } } return sum; From dc89bdd3f0ba03015eaeb38191467b5bc33060b0 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Sun, 21 Apr 2013 16:06:12 +0900 Subject: [PATCH 19/33] Fix unexpected sign extension --- taglib/toolkit/tbytevector.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index f1ca4c78..fafaf68f 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -227,18 +227,13 @@ T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignifica return 0; } - if(length >= sizeof(T)) { - return toNumber(v, offset, mostSignificantByteFirst); + 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; } - else { - 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); - } - return sum; - } + return sum; } template From 49b07a26626a2d1741c7b04073fd2016963f3766 Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Sun, 21 Apr 2013 22:24:12 +0900 Subject: [PATCH 20/33] Refactor out some stuff to CMake tests --- CMakeLists.txt | 1 - ConfigureChecks.cmake | 170 +++++++++++++++++- config-taglib.h.cmake | 38 +++- taglib/CMakeLists.txt | 2 - taglib/asf/asfattribute.cpp | 4 - taglib/asf/asffile.cpp | 4 - taglib/asf/asfpicture.cpp | 4 - taglib/asf/asfproperties.cpp | 4 +- taglib/asf/asftag.cpp | 4 +- taglib/fileref.cpp | 4 +- taglib/flac/flacmetadatablock.cpp | 4 - taglib/flac/flacpicture.cpp | 4 - taglib/flac/flacunknownmetadatablock.cpp | 4 - taglib/mp4/mp4atom.cpp | 4 - taglib/mp4/mp4coverart.cpp | 4 - taglib/mp4/mp4file.cpp | 4 - taglib/mp4/mp4item.cpp | 4 - taglib/mp4/mp4properties.cpp | 4 +- taglib/mp4/mp4tag.cpp | 4 +- taglib/mpeg/id3v2/id3v2frame.cpp | 4 +- taglib/mpeg/id3v2/id3v2framefactory.cpp | 4 +- taglib/toolkit/taglib.h | 163 +++++++++++------ taglib/toolkit/tbyteswap.cpp | 197 --------------------- taglib/toolkit/tbyteswap.h | 55 ------ taglib/toolkit/tbytevector.cpp | 55 +++++- taglib/toolkit/tstring.cpp | 215 +++++++++++++---------- 26 files changed, 478 insertions(+), 486 deletions(-) delete mode 100644 taglib/toolkit/tbyteswap.cpp delete mode 100644 taglib/toolkit/tbyteswap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f29e463..14f00956 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,6 @@ option(BUILD_EXAMPLES "Build the examples" OFF) option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF) -add_definitions(-DHAVE_CONFIG_H) set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/") ## the following are directories where stuff will be installed to diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 4b8f512e..11db70d8 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -5,8 +5,170 @@ include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckCXXSourceCompiles) +include(TestBigEndian) + +# Determine the CPU byte order. + +test_big_endian(TAGLIB_BIG_ENDIAN) + +if(NOT ${TAGLIB_BIG_ENDIAN}) +set(TAGLIB_LITTLE_ENDIAN 1) +endif() + +# Determine the size of integral types. + +check_type_size("short" SIZEOF_SHORT) +check_type_size("int" SIZEOF_INT) +check_type_size("long long" SIZEOF_LONGLONG) +check_type_size("wchar_t" SIZEOF_WCHAR_T) + +# Determine if your compiler supports std::wstring. + +check_cxx_source_compiles(" + #include + int main() { + std::wstring x(L\"ABC\"); + return 0; + } +" HAVE_STD_WSTRING) + +# Determine which kind of atomic operations your compiler supports. + +check_cxx_source_compiles(" + #include + int main() { + std::atomic x; + x.fetch_add(1); + x.fetch_sub(1); + return 0; + } +" HAVE_STD_ATOMIC) + +check_cxx_source_compiles(" + #include + int main() { + boost::atomic x(1); + x.fetch_add(1); + x.fetch_sub(1); + return 0; + } +" HAVE_BOOST_ATOMIC) + +check_cxx_source_compiles(" + int main() { + volatile int x; + __sync_add_and_fetch(&x, 1); + int y = __sync_sub_and_fetch(&x, 1); + return 0; + } +" HAVE_GCC_ATOMIC) + +check_cxx_source_compiles(" + #include + int main() { + volatile int32_t x; + OSAtomicIncrement32Barrier(&x); + int32_t y = OSAtomicDecrement32Barrier(&x); + return 0; + } +" HAVE_MAC_ATOMIC) + +check_cxx_source_compiles(" + #include + int main() { + volatile LONG x; + InterlockedIncrement(&x); + LONG y = InterlockedDecrement(&x); + return 0; + } +" HAVE_WIN_ATOMIC) + +check_cxx_source_compiles(" + #include + int main() { + volatile int x; + __sync_add_and_fetch(&x, 1); + int y = __sync_sub_and_fetch(&x, 1); + return 0; + } +" HAVE_IA64_ATOMIC) + +# Determine which kind of byte swap functions your compiler supports. + +# Some of them can be missing depends on the GCC version. +check_cxx_source_compiles(" + int main() { + __builtin_bswap16(0); + return 0; + } +" HAVE_GCC_BYTESWAP_16) + +check_cxx_source_compiles(" + int main() { + __builtin_bswap32(0); + return 0; + } +" HAVE_GCC_BYTESWAP_32) + +check_cxx_source_compiles(" + int main() { + __builtin_bswap64(0); + return 0; + } +" HAVE_GCC_BYTESWAP_64) + +check_cxx_source_compiles(" + #include + int main() { + _byteswap_ushort(0); + _byteswap_ulong(0); + _byteswap_uint64(0); + return 0; + } +" HAVE_MSC_BYTESWAP) + +check_cxx_source_compiles(" + #include + int main() { + __bswap_16(0); + __bswap_32(0); + __bswap_64(0); + return 0; + } +" HAVE_GLIBC_BYTESWAP) + +check_cxx_source_compiles(" + #include + int main() { + OSSwapInt16(0); + OSSwapInt32(0); + OSSwapInt64(0); + return 0; + } +" HAVE_MAC_BYTESWAP) + +check_cxx_source_compiles(" + #include + int main() { + swap16(0); + swap32(0); + swap64(0); + return 0; + } +" HAVE_OPENBSD_BYTESWAP) + +# Determine whether your compiler supports codecvt. + +check_cxx_source_compiles(" + #include + int main() { + std::codecvt_utf8_utf16 x; + return 0; + } +" HAVE_STD_CODECVT) + +# Check for libz using the cmake supplied FindZLIB.cmake -# check for libz using the cmake supplied FindZLIB.cmake find_package(ZLIB) if(ZLIB_FOUND) set(HAVE_ZLIB 1) @@ -14,12 +176,6 @@ else() set(HAVE_ZLIB 0) endif() -# Determine whether your compiler supports codecvt header. - -check_cxx_source_compiles(" - #include - int main() { std::codecvt_utf8_utf16 x; return 0; } -" HAVE_CODECVT) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index 9fcc29a4..bb25bb86 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -1,10 +1,40 @@ /* config-taglib.h. Generated by cmake from config-taglib.h.cmake */ -/* Define if you have libz */ -#cmakedefine HAVE_ZLIB 1 +/* Indicates the endianness of your target system */ +#cmakedefine TAGLIB_LITTLE_ENDIAN 1 +#cmakedefine TAGLIB_BIG_ENDIAN 1 -/* Defined if your compiler has header */ -#cmakedefine HAVE_CODECVT 1 +/* Size of integral types */ +#cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT} +#cmakedefine SIZEOF_INT ${SIZEOF_INT} +#cmakedefine SIZEOF_LONGLONG ${SIZEOF_LONGLONG} +#cmakedefine SIZEOF_WCHAR_T ${SIZEOF_WCHAR_T} + +/* Defined if your compiler supports std::wstring */ +#cmakedefine HAVE_STD_WSTRING 1 + +/* Defined if your compiler supports some atomic operations */ +#cmakedefine HAVE_STD_ATOMIC 1 +#cmakedefine HAVE_BOOST_ATOMIC 1 +#cmakedefine HAVE_GCC_ATOMIC 1 +#cmakedefine HAVE_MAC_ATOMIC 1 +#cmakedefine HAVE_WIN_ATOMIC 1 +#cmakedefine HAVE_IA64_ATOMIC 1 + +/* Defined if your compiler supports some byte swap functions */ +#cmakedefine HAVE_GCC_BYTESWAP_16 1 +#cmakedefine HAVE_GCC_BYTESWAP_32 1 +#cmakedefine HAVE_GCC_BYTESWAP_64 1 +#cmakedefine HAVE_MSC_BYTESWAP 1 +#cmakedefine HAVE_GLIBC_BYTESWAP 1 +#cmakedefine HAVE_MAC_BYTESWAP 1 +#cmakedefine HAVE_OPENBSD_BYTESWAP 1 + +/* Defined if your compiler supports codecvt */ +#cmakedefine HAVE_STD_CODECVT 1 + +/* Defined if you have libz */ +#cmakedefine HAVE_ZLIB 1 #cmakedefine NO_ITUNES_HACKS 1 #cmakedefine WITH_ASF 1 diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index a940caf5..72712ca2 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -50,7 +50,6 @@ set(tag_HDRS toolkit/tmap.h toolkit/tmap.tcc toolkit/tpropertymap.h - toolkit/tbyteswap.h mpeg/mpegfile.h mpeg/mpegproperties.h mpeg/mpegheader.h @@ -290,7 +289,6 @@ set(toolkit_SRCS toolkit/tfilestream.cpp toolkit/tdebug.cpp toolkit/tpropertymap.cpp - toolkit/tbyteswap.cpp toolkit/unicode.cpp ) diff --git a/taglib/asf/asfattribute.cpp b/taglib/asf/asfattribute.cpp index 2cfada7b..937a8816 100644 --- a/taglib/asf/asfattribute.cpp +++ b/taglib/asf/asfattribute.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "asfattribute.h" diff --git a/taglib/asf/asffile.cpp b/taglib/asf/asffile.cpp index 56e93a76..241998ca 100644 --- a/taglib/asf/asffile.cpp +++ b/taglib/asf/asffile.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include diff --git a/taglib/asf/asfpicture.cpp b/taglib/asf/asfpicture.cpp index 35e52a7d..3db695a4 100644 --- a/taglib/asf/asfpicture.cpp +++ b/taglib/asf/asfpicture.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "asfattribute.h" diff --git a/taglib/asf/asfproperties.cpp b/taglib/asf/asfproperties.cpp index 835cbdf9..11d43b9d 100644 --- a/taglib/asf/asfproperties.cpp +++ b/taglib/asf/asfproperties.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include diff --git a/taglib/asf/asftag.cpp b/taglib/asf/asftag.cpp index 1cbd16eb..70881209 100644 --- a/taglib/asf/asftag.cpp +++ b/taglib/asf/asftag.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include "asftag.h" diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 46e59ff1..6da560b7 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -27,9 +27,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif +#include #ifdef _WIN32 # include diff --git a/taglib/flac/flacmetadatablock.cpp b/taglib/flac/flacmetadatablock.cpp index 7d161c27..17ab05f3 100644 --- a/taglib/flac/flacmetadatablock.cpp +++ b/taglib/flac/flacmetadatablock.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "flacmetadatablock.h" diff --git a/taglib/flac/flacpicture.cpp b/taglib/flac/flacpicture.cpp index 95eeb6ab..a2a9000b 100644 --- a/taglib/flac/flacpicture.cpp +++ b/taglib/flac/flacpicture.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "flacpicture.h" diff --git a/taglib/flac/flacunknownmetadatablock.cpp b/taglib/flac/flacunknownmetadatablock.cpp index 1265affb..dcd5d651 100644 --- a/taglib/flac/flacunknownmetadatablock.cpp +++ b/taglib/flac/flacunknownmetadatablock.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include diff --git a/taglib/mp4/mp4atom.cpp b/taglib/mp4/mp4atom.cpp index fac593b1..7b87a479 100644 --- a/taglib/mp4/mp4atom.cpp +++ b/taglib/mp4/mp4atom.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "mp4atom.h" diff --git a/taglib/mp4/mp4coverart.cpp b/taglib/mp4/mp4coverart.cpp index 928e3c4a..5ccc76d6 100644 --- a/taglib/mp4/mp4coverart.cpp +++ b/taglib/mp4/mp4coverart.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "mp4coverart.h" diff --git a/taglib/mp4/mp4file.cpp b/taglib/mp4/mp4file.cpp index f41ee888..aab1a2be 100644 --- a/taglib/mp4/mp4file.cpp +++ b/taglib/mp4/mp4file.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include diff --git a/taglib/mp4/mp4item.cpp b/taglib/mp4/mp4item.cpp index af2cc65c..fdb96451 100644 --- a/taglib/mp4/mp4item.cpp +++ b/taglib/mp4/mp4item.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "mp4item.h" diff --git a/taglib/mp4/mp4properties.cpp b/taglib/mp4/mp4properties.cpp index e4e95072..f5d7ed21 100644 --- a/taglib/mp4/mp4properties.cpp +++ b/taglib/mp4/mp4properties.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index df83796d..e16a994b 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index c5c5585d..a444b9eb 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #if HAVE_ZLIB #include diff --git a/taglib/mpeg/id3v2/id3v2framefactory.cpp b/taglib/mpeg/id3v2/id3v2framefactory.cpp index c7d74214..54b37ce8 100644 --- a/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ b/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index dd4ee69d..81d23f04 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -26,6 +26,8 @@ #ifndef TAGLIB_H #define TAGLIB_H +#include "config.h" + #define TAGLIB_MAJOR_VERSION 1 #define TAGLIB_MINOR_VERSION 8 #define TAGLIB_PATCH_VERSION 0 @@ -45,47 +47,110 @@ #include #include -#ifdef __APPLE__ -# include -# define TAGLIB_ATOMIC_MAC -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if !defined(NOMINMAX) -# define NOMINMAX -# endif -# include -# define TAGLIB_ATOMIC_WIN -#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ - && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ - defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ - && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -#elif defined(__ia64) && defined(__INTEL_COMPILER) -# include -# define TAGLIB_ATOMIC_GCC -#endif - // Check the widths of integral types. -#if UCHAR_MAX != 255U -# error TagLib assumes that char is 8-bit wide. +#if SIZEOF_SHORT != 2 +# error TagLib requires that short is 16-bit wide. #endif -#if USHRT_MAX != 65535U -# error TagLib assumes that short is 16-bit wide. +#if SIZEOF_INT != 4 +# error TagLib requires that int is 32-bit wide. #endif -#if UINT_MAX != 4294967295U -# error TagLib assumes that int is 32-bit wide. +#if SIZEOF_LONGLONG != 8 +# error TagLib requires that long long is 64-bit wide. #endif -#if !defined(ULLONG_MAX) && !defined(ULONGLONG_MAX) && !defined(ULONG_LONG_MAX) -# error TagLib assumes that long long is 64-bit wide. -#elif defined(ULLONG_MAX) && ULLONG_MAX != 18446744073709551615ULL -# error TagLib assumes that long long is 64-bit wide. -#elif defined(ULONGLONG_MAX) && ULONGLONG_MAX != 18446744073709551615ULL -# error TagLib assumes that long long is 64-bit wide. -#elif defined(ULONG_LONG_MAX) && ULONG_LONG_MAX != 18446744073709551615ULL -# error TagLib assumes that long long is 64-bit wide. +#if SIZEOF_WCHAR_T < 2 +# error TagLib requires that wchar_t is sufficient to store a UTF-16 char. +#endif + +// Atomic increment/decrement operations + +#if defined(HAVE_STD_ATOMIC) +# include +#elif defined(HAVE_BOOST_ATOMIC) +# include +#elif defined(HAVE_MAC_ATOMIC) +# include +#elif defined(HAVE_WIN_ATOMIC) +# include +#elif defined(HAVE_IA64_ATOMIC) +# include +#endif + +#if defined(HAVE_STD_ATOMIC) +# define TAGLIB_ATOMIC_INT std::atomic +# define TAGLIB_ATOMIC_INC(x) x.fetch_add(1) +# define TAGLIB_ATOMIC_DEC(x) (x.fetch_sub(1) - 1) +#elif defined(HAVE_BOOST_ATOMIC) +# define TAGLIB_ATOMIC_INT boost::atomic +# define TAGLIB_ATOMIC_INC(x) x.fetch_add(1) +# define TAGLIB_ATOMIC_DEC(x) (x.fetch_sub(1) - 1) +#elif defined(HAVE_GCC_ATOMIC) +# define TAGLIB_ATOMIC_INT volatile int +# define TAGLIB_ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) +# define TAGLIB_ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +#elif defined(HAVE_MAC_ATOMIC) +# define TAGLIB_ATOMIC_INT volatile int32_t +# define TAGLIB_ATOMIC_INC(x) OSAtomicIncrement32Barrier(&x) +# define TAGLIB_ATOMIC_DEC(x) OSAtomicDecrement32Barrier(&x) +#elif defined(HAVE_IA64_ATOMIC) +# define TAGLIB_ATOMIC_INT volatile int +# define TAGLIB_ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) +# define TAGLIB_ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +#else +# define TAGLIB_ATOMIC_INT volatile int +# define TAGLIB_ATOMIC_INC(x) (++x) +# define TAGLIB_ATOMIC_DEC(x) (--x) +#endif + +// Optimized byte swap functions. + +#if defined(HAVE_MSC_BYTESWAP) +# include +#elif defined(HAVE_GLIBC_BYTESWAP) +# include +#elif defined(HAVE_MAC_BYTESWAP) +# include +#elif defined(HAVE_OPENBSD_BYTESWAP) +# include +#endif + +#if defined(HAVE_GCC_BYTESWAP16) +# define TAGLIB_BYTESWAP_16(x) __builtin_bswap16(x) +#elif defined(HAVE_MSC_BYTESWAP) +# define TAGLIB_BYTESWAP_16(x) _byteswap_ushort(x) +#elif defined(HAVE_GLIBC_BYTESWAP) +# define TAGLIB_BYTESWAP_16(x) __bswap_16(x) +#elif defined(HAVE_MAC_BYTESWAP) +# define TAGLIB_BYTESWAP_16(x) OSSwapInt16(x) +#elif defined(HAVE_OPENBSD_BYTESWAP) +# define TAGLIB_BYTESWAP_16(x) swap16(x) +#endif + +#if defined(HAVE_GCC_BYTESWAP32) +# define TAGLIB_BYTESWAP_32(x) __builtin_bswap32(x) +#elif defined(HAVE_MSC_BYTESWAP) +# define TAGLIB_BYTESWAP_32(x) _byteswap_ulong(x) +#elif defined(HAVE_GLIBC_BYTESWAP) +# define TAGLIB_BYTESWAP_32(x) __bswap_32(x) +#elif defined(HAVE_MAC_BYTESWAP) +# define TAGLIB_BYTESWAP_32(x) OSSwapInt32(x) +#elif defined(HAVE_OPENBSD_BYTESWAP) +# define TAGLIB_BYTESWAP_32(x) swap32(x) +#endif + +#if defined(HAVE_GCC_BYTESWAP64) +# define TAGLIB_BYTESWAP_64(x) __builtin_bswap64(x) +#elif defined(HAVE_MSC_BYTESWAP) +# define TAGLIB_BYTESWAP_64(x) _byteswap_uint64(x) +#elif defined(HAVE_GLIBC_BYTESWAP) +# define TAGLIB_BYTESWAP_64(x) __bswap_64(x) +#elif defined(HAVE_MAC_BYTESWAP) +# define TAGLIB_BYTESWAP_64(x) OSSwapInt64(x) +#elif defined(HAVE_OPENBSD_BYTESWAP) +# define TAGLIB_BYTESWAP_64(x) swap64(x) #endif //! A namespace for all TagLib related classes and functions @@ -115,7 +180,11 @@ namespace TagLib { * Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3) * so I'm providing something here that should be constant. */ +#ifdef HAVE_STD_WSTRING + typedef std::wstring wstring; +#else typedef std::basic_string wstring; +#endif #ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. /*! @@ -130,32 +199,12 @@ namespace TagLib { public: RefCounter() : refCount(1) {} -#ifdef TAGLIB_ATOMIC_MAC - void ref() { OSAtomicIncrement32Barrier(const_cast(&refCount)); } - bool deref() { return ! OSAtomicDecrement32Barrier(const_cast(&refCount)); } - int32_t count() { return refCount; } - private: - volatile int32_t refCount; -#elif defined(TAGLIB_ATOMIC_WIN) - void ref() { InterlockedIncrement(&refCount); } - bool deref() { return ! InterlockedDecrement(&refCount); } - long count() { return refCount; } - private: - volatile long refCount; -#elif defined(TAGLIB_ATOMIC_GCC) - void ref() { __sync_add_and_fetch(&refCount, 1); } - bool deref() { return ! __sync_sub_and_fetch(&refCount, 1); } + void ref() { TAGLIB_ATOMIC_INC(refCount); } + bool deref() { return (TAGLIB_ATOMIC_DEC(refCount) == 0); } int count() { return refCount; } - private: - volatile int refCount; -#else - void ref() { refCount++; } - bool deref() { return ! --refCount; } - int count() { return refCount; } - private: - uint refCount; -#endif + private: + TAGLIB_ATOMIC_INT refCount; }; #endif // DO_NOT_DOCUMENT diff --git a/taglib/toolkit/tbyteswap.cpp b/taglib/toolkit/tbyteswap.cpp deleted file mode 100644 index cee2772d..00000000 --- a/taglib/toolkit/tbyteswap.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "taglib.h" -#include "tbyteswap.h" - -// Determines if compiler intrinsic functions are available. - -// MSVC: Intrinsic _byteswap_* functions. -#if defined(_MSC_VER) && _MSC_VER >= 1400 -# include -# define TAGLIB_BYTESWAP_MSC - -// GCC 4.8 or above: __builtin_bswap16(), 32 and 64. -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) -# define TAGLIB_BYTESWAP_GCC 2 - -// GCC 4.3 or above: __builtin_bswap16 is missing. -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) -# define TAGLIB_BYTESWAP_GCC 1 - -#endif - -// Determines if platform or library specific functions are available. - -#if defined(__APPLE__) -# include -# define TAGLIB_BYTESWAP_MAC - -#elif defined(__OpenBSD__) -# include -# define TAGLIB_BYTESWAP_OPENBSD - -#elif defined(__GLIBC__) -# include -# define TAGLIB_BYTESWAP_GLIBC - -#endif - -// Determines CPU byte order at compile time rather than run time if possible. - -#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) \ - || (defined(__GNUC__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \ - || (defined(__clang__) && defined(__LITTLE_ENDIAN__)) -# define TAGLIB_LITTLE_ENDIAN - -#elif (defined(__GNUC__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) \ - || (defined(__clang__) && defined(__BIG_ENDIAN__)) -# define TAGLIB_BIG_ENDIAN - -#else - -namespace { - bool isLittleEndian() - { - TagLib::ushort x = 1; - return (*reinterpret_cast(&x) == 1); - } -} - -#endif - -namespace TagLib -{ - ushort byteSwap16(ushort x) - { -#if defined(TAGLIB_BYTESWAP_MSC) - - return _byteswap_ushort(x); - -#elif defined(TAGLIB_BYTESWAP_GCC) && TAGLIB_BYTESWAP_GCC == 2 - - return __builtin_bswap16(x); - -#elif defined(TAGLIB_BYTESWAP_MAC) - - return OSSwapInt16(x); - -#elif defined(TAGLIB_BYTESWAP_OPENBSD) - - return swap16(x); - -#elif defined(TAGLIB_BYTESWAP_GLIBC) - - return __bswap_16(x); - -#else - - return ((x >> 8) & 0xff) | ((x & 0xff) << 8); - -#endif - } - - uint byteSwap32(uint x) - { -#if defined(TAGLIB_BYTESWAP_MSC) - - return _byteswap_ulong(x); - -#elif defined(TAGLIB_BYTESWAP_GCC) - - return __builtin_bswap32(x); - -#elif defined(TAGLIB_BYTESWAP_MAC) - - return OSSwapInt32(x); - -#elif defined(TAGLIB_BYTESWAP_OPENBSD) - - return swap32(x); - -#elif defined(TAGLIB_BYTESWAP_GLIBC) - - return __bswap_32(x); - -#else - - return ((x & 0xff000000) >> 24) - | ((x & 0x00ff0000) >> 8) - | ((x & 0x0000ff00) << 8) - | ((x & 0x000000ff) << 24); - -#endif - } - - ulonglong byteSwap64(ulonglong x) - { -#if defined(TAGLIB_BYTESWAP_MSC) - - return _byteswap_uint64(x); - -#elif defined(TAGLIB_BYTESWAP_GCC) - - return __builtin_bswap64(x); - -#elif defined(TAGLIB_BYTESWAP_MAC) - - return OSSwapInt64(x); - -#elif defined(TAGLIB_BYTESWAP_OPENBSD) - - return swap64(x); - -#elif defined(TAGLIB_BYTESWAP_GLIBC) - - return __bswap_64(x); - -#else - - return ((x & 0xff00000000000000ull) >> 56) - | ((x & 0x00ff000000000000ull) >> 40) - | ((x & 0x0000ff0000000000ull) >> 24) - | ((x & 0x000000ff00000000ull) >> 8) - | ((x & 0x00000000ff000000ull) << 8) - | ((x & 0x0000000000ff0000ull) << 24) - | ((x & 0x000000000000ff00ull) << 40) - | ((x & 0x00000000000000ffull) << 56); - -#endif - } - -#if defined(TAGLIB_LITTLE_ENDIAN) - - const bool isLittleEndianSystem = true; - -#elif defined(TAGLIB_BIG_ENDIAN) - - const bool isLittleEndianSystem = false; - -#else - - const bool isLittleEndianSystem = isLittleEndian(); - -#endif -} diff --git a/taglib/toolkit/tbyteswap.h b/taglib/toolkit/tbyteswap.h deleted file mode 100644 index 012a3173..00000000 --- a/taglib/toolkit/tbyteswap.h +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_BYTESWAP_H -#define TAGLIB_BYTESWAP_H - -namespace TagLib -{ - // Cross-platform byte order conversion functions. - - /*! - * Converts the byte order of \a x as a 16-bit unsigned integer. - */ - ushort byteSwap16(ushort x); - - /*! - * Converts the byte order of \a x as a 32-bit unsigned integer. - */ - uint byteSwap32(uint x); - - /*! - * Converts the byte order of \a x as a 64-bit unsigned integer. - */ - ulonglong byteSwap64(ulonglong x); - - /*! - * Indicates the system byte order. - * \a true if little endian, \a false if big endian. - */ - extern const bool isLittleEndianSystem; -} - -#endif diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index fafaf68f..a4b12672 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -30,7 +30,6 @@ #include #include "tbytevector.h" -#include "tbyteswap.h" // This is a bit ugly to keep writing over and over again. @@ -186,19 +185,53 @@ T byteSwap(T x) template <> ushort byteSwap(ushort x) { - return byteSwap16(x); +#ifdef TAGLIB_BYTESWAP_16 + + return TAGLIB_BYTESWAP_16(x); + +#else + + return ((x >> 8) & 0xff) | ((x & 0xff) << 8); + +#endif } template <> uint byteSwap(uint x) { - return byteSwap32(x); +#ifdef TAGLIB_BYTESWAP_32 + + return TAGLIB_BYTESWAP_32(x); + +#else + + return ((x & 0xff000000u) >> 24) + | ((x & 0x00ff0000u) >> 8) + | ((x & 0x0000ff00u) << 8) + | ((x & 0x000000ffu) << 24); + +#endif } template <> ulonglong byteSwap(ulonglong x) { - return byteSwap64(x); +#ifdef TAGLIB_BYTESWAP_64 + + return TAGLIB_BYTESWAP_64(x); + +#else + + return (x & 0xff00000000000000ull) >> 56) + | (x & 0x00ff000000000000ull) >> 40) + | (x & 0x0000ff0000000000ull) >> 24) + | (x & 0x000000ff00000000ull) >> 8) + | (x & 0x00000000ff000000ull) << 8) + | (x & 0x0000000000ff0000ull) << 24) + | (x & 0x000000000000ff00ull) << 40) + | (x & 0x00000000000000ffull) << 56); + +#endif } template @@ -213,7 +246,12 @@ T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) T tmp; ::memcpy(&tmp, v.data() + offset, sizeof(T)); - if(isLittleEndianSystem == mostSignificantByteFirst) +#ifdef TAGLIB_LITTLE_ENDIAN + const bool swap = mostSignificantByteFirst; +#else + const bool swap != mostSignificantByteFirst; +#endif + if(swap) return byteSwap(tmp); else return tmp; @@ -241,7 +279,12 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst) { const size_t size = sizeof(T); - if(isLittleEndianSystem == mostSignificantByteFirst) +#ifdef TAGLIB_LITTLE_ENDIAN + const bool swap = mostSignificantByteFirst; +#else + const bool swap != mostSignificantByteFirst; +#endif + if(swap) value = byteSwap(value); return ByteVector(reinterpret_cast(&value), size); diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 22590c89..72f4a24a 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -25,33 +25,128 @@ // This class assumes that std::basic_string has a contiguous and null-terminated buffer. -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #include "tstring.h" #include "tdebug.h" #include "tstringlist.h" -#include "tbyteswap.h" #include #include -#ifdef HAVE_CODECVT +#ifdef HAVE_STD_CODECVT # include -namespace { - typedef std::codecvt_utf8_utf16 utf8_utf16_t; -} #else # include "unicode.h" #endif -namespace { +namespace +{ + inline TagLib::ushort byteSwap(TagLib::ushort x) + { +#ifdef TAGLIB_BYTESWAP_16 + + return TAGLIB_BYTESWAP_16(x); + +#else + + return((x >> 8) & 0xff) | ((x & 0xff) << 8); + +#endif + } inline unsigned short combine(unsigned char c1, unsigned char c2) { return (c1 << 8) | c2; } + + void UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) + { +#ifdef HAVE_STD_CODECVT + + typedef std::codecvt_utf8_utf16 utf8_utf16_t; + + using namespace TagLib; + + const wchar_t *srcBegin = src; + const wchar_t *srcEnd = srcBegin + srcLength; + + char *dstBegin = dst; + char *dstEnd = dstBegin + dstLength; + + std::mbstate_t st = 0; + const wchar_t *source; + char *target; + std::codecvt_base::result result = utf8_utf16_t().out( + st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); + + if(result != utf8_utf16_t::ok) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#else + + using namespace Unicode; + using namespace TagLib; + + const Unicode::UTF16 *srcBegin = src; + const Unicode::UTF16 *srcEnd = srcBegin + srcLength; + + Unicode::UTF8 *dstBegin = reinterpret_cast(dst); + Unicode::UTF8 *dstEnd = dstBegin + dstLength; + + Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( + &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::to8Bit() - Unicode conversion error."); + } + +#endif + } + + void UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) + { +#ifdef HAVE_STD_CODECVT + + typedef std::codecvt_utf8_utf16 utf8_utf16_t; + + using namespace TagLib; + + const char *srcBegin = src; + const char *srcEnd = srcBegin + srcLength; + + wchar_t *dstBegin = dst; + wchar_t *dstEnd = dstBegin + dstLength; + + std::mbstate_t st = 0; + const char *source; + wchar_t *target; + std::codecvt_base::result result = utf8_utf16_t().in( + st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); + + if(result != utf8_utf16_t::ok) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#else + + using namespace Unicode; + using namespace TagLib; + + const Unicode::UTF8 *srcBegin = reinterpret_cast(src); + const Unicode::UTF8 *srcEnd = srcBegin + srcLength; + + Unicode::UTF16 *dstBegin = dst; + Unicode::UTF16 *dstEnd = dstBegin + dstLength; + + Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( + &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#endif + } } namespace TagLib { @@ -202,34 +297,7 @@ std::string String::to8Bit(bool unicode) const else { s.resize(d->data.size() * 4 + 1); -#ifdef HAVE_CODECVT - - std::mbstate_t st = 0; - const wchar_t *source; - char *target; - std::codecvt_base::result result = utf8_utf16_t().out( - st, &d->data[0], &d->data[d->data.size()], source, &s[0], &s[s.size()], target); - - if(result != utf8_utf16_t::ok) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#else - - const Unicode::UTF16 *source = &d->data[0]; - Unicode::UTF8 *target = reinterpret_cast(&s[0]); - - Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( - &source, source + d->data.size(), - &target, target + s.size(), - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::to8Bit() - Unicode conversion error."); - } - -#endif - + UTF16toUTF8(&d->data[0], d->data.size(), &s[0], s.size()); s.resize(::strlen(s.c_str())); } @@ -371,34 +439,7 @@ ByteVector String::data(Type t) const { ByteVector v(size() * 4 + 1, 0); -#ifdef HAVE_CODECVT - - std::mbstate_t st = 0; - const wchar_t *source; - char *target; - std::codecvt_base::result result = utf8_utf16_t().out( - st, &d->data[0], &d->data[d->data.size()], source, v.data(), v.data() + v.size(), target); - - if(result != utf8_utf16_t::ok) { - debug("String::data() - Unicode conversion error."); - } - -#else - - const Unicode::UTF16 *source = &d->data[0]; - Unicode::UTF8 *target = reinterpret_cast(v.data()); - - Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( - &source, source + d->data.size(), - &target, target + v.size(), - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::data() - Unicode conversion error."); - } - -#endif - + UTF16toUTF8(&d->data[0], d->data.size(), v.data(), v.size()); v.resize(::strlen(v.data())); return v; @@ -730,34 +771,7 @@ void String::copyFromUTF8(const char *s, size_t length) { d->data.resize(length); -#ifdef HAVE_CODECVT - - std::mbstate_t st = 0; - const char *source; - wchar_t *target; - std::codecvt_base::result result = utf8_utf16_t().in( - st, s, s + length, source, &d->data[0], &d->data[d->data.size()], target); - - if(result != utf8_utf16_t::ok) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#else - - const Unicode::UTF8 *source = reinterpret_cast(s); - Unicode::UTF16 *target = &d->data[0]; - - Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( - &source, source + length, - &target, target + length, - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#endif - + UTF8toUTF16(s, length, &d->data[0], d->data.size()); d->data.resize(::wcslen(d->data.c_str())); } @@ -785,7 +799,7 @@ void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) if(swap) { for(size_t i = 0; i < length; ++i) - d->data[i] = byteSwap16(static_cast(s[i])); + d->data[i] = byteSwap(static_cast(s[i])); } } @@ -836,7 +850,16 @@ void String::copyFromUTF16(const char *s, size_t length, Type t) #endif } -const String::Type String::WCharByteOrder = isLittleEndianSystem ? String::UTF16LE : String::UTF16BE; +#ifdef TAGLIB_LITTLE_ENDIAN + +const String::Type String::WCharByteOrder = String::UTF16LE; + +#else + +const String::Type String::WCharByteOrder = String::UTF16BE; + +#endif + } //////////////////////////////////////////////////////////////////////////////// From c2896fd62967d1f80ddbe6b3c96bc7f30fd3d3d9 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 22 Apr 2013 08:01:25 +0900 Subject: [PATCH 21/33] Improve getting file size in Win32 --- taglib/toolkit/tfilestream.cpp | 42 +++++++++++++++++++++++----------- taglib/toolkit/tiostream.h | 4 ++-- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index c008c190..d89714a0 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -43,16 +43,15 @@ using namespace TagLib; -namespace { +namespace +{ #ifdef _WIN32 - // For Windows + // Using Win32 native API instead of standard C file I/O to reduce the resource consumption. typedef FileName FileNameHandle; - // Using native file handles instead of file descriptors for reducing the resource consumption. - - const HANDLE InvalidFile = INVALID_HANDLE_VALUE; +# define INVALID_FILE INVALID_HANDLE_VALUE HANDLE openFile(const FileName &path, bool readOnly) { @@ -60,8 +59,10 @@ namespace { if(!path.wstr().empty()) return CreateFileW(path, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - else + else if(!path.str().empty()) return CreateFileA(path, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + else + return INVALID_FILE; } size_t fread(void *ptr, size_t size, size_t nmemb, HANDLE stream) @@ -114,9 +115,7 @@ namespace { #else - // For non-Windows - - FILE *const InvalidFile = 0; +# define INVALID_FILE 0 struct FileNameHandle : public std::string { @@ -155,7 +154,7 @@ public: }; FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool openReadOnly) : - file(InvalidFile), + file(INVALID_FILE), name(fileName), readOnly(true), size(0) @@ -165,12 +164,12 @@ FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool if(!openReadOnly) file = openFile(name, false); - if(file != InvalidFile) + if(file != INVALID_FILE) readOnly = false; else file = openFile(name, true); - if(file == InvalidFile) + if(file == INVALID_FILE) { # ifdef _WIN32 @@ -398,7 +397,7 @@ bool FileStream::readOnly() const bool FileStream::isOpen() const { - return (d->file != InvalidFile); + return (d->file != INVALID_FILE); } void FileStream::seek(long offset, Position p) @@ -489,6 +488,21 @@ long FileStream::length() if(d->size > 0) return d->size; +#ifdef _WIN32 + + LARGE_INTEGER fileSize; + if(GetFileSizeEx(d->file, &fileSize)) { + d->size = static_cast(fileSize.QuadPart); + return d->size; + } + else { + debug("File::length() -- Failed to get the file size."); + d->size = 0; + return 0; + } + +#else + const long curpos = tell(); seek(0, End); @@ -498,6 +512,8 @@ long FileStream::length() d->size = endpos; return endpos; + +#endif } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index ee43154b..d3f78c28 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -49,8 +49,8 @@ namespace TagLib { const std::string &str() const { return m_name; } private: - std::string m_name; - std::wstring m_wname; + const std::string m_name; + const std::wstring m_wname; }; #else typedef const char *FileName; From 3e89f7cb4071fcd01c0d4d0db45a96a4b502fe5a Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 23 Apr 2013 00:15:54 +0900 Subject: [PATCH 22/33] Fix a change breaks compatibility with Win9x --- taglib/toolkit/tfilestream.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index d89714a0..cd9dd7dd 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -490,9 +490,9 @@ long FileStream::length() #ifdef _WIN32 - LARGE_INTEGER fileSize; - if(GetFileSizeEx(d->file, &fileSize)) { - d->size = static_cast(fileSize.QuadPart); + const DWORD fileSize = GetFileSize(d->file, NULL); + if(GetLastError() != ERROR_SUCCESS) { + d->size = static_cast(fileSize); return d->size; } else { From 986ee3c44aff2ac68e7b8001a50abdf824cda5de Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 23 Apr 2013 01:59:02 +0900 Subject: [PATCH 23/33] Improve Unicode file name handling in Win9x --- taglib/toolkit/tfilestream.cpp | 4 +- taglib/toolkit/tiostream.cpp | 91 ++++++++++++++++++++++++++++++++++ taglib/toolkit/tiostream.h | 15 +++--- 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index cd9dd7dd..a8de32aa 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -58,9 +58,9 @@ namespace const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); if(!path.wstr().empty()) - return CreateFileW(path, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); else if(!path.str().empty()) - return CreateFileA(path, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); else return INVALID_FILE; } diff --git a/taglib/toolkit/tiostream.cpp b/taglib/toolkit/tiostream.cpp index e7b60dd7..2d4f66d8 100644 --- a/taglib/toolkit/tiostream.cpp +++ b/taglib/toolkit/tiostream.cpp @@ -27,6 +27,97 @@ using namespace TagLib; +#ifdef _WIN32 + +// MSVC 2008 or later can't produce the binary for Win9x. +#if !defined(_MSC_VER) || (_MSC_VER < 1500) + +namespace +{ + + // Determines whether or not the running system is WinNT. + // In other words, whether the system supports Unicode. + + bool isWinNT() + { + OSVERSIONINFOA ver = {}; + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if(GetVersionExA(&ver)) { + return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT); + } + else { + return false; + } + } + + const bool IsWinNT = isWinNT(); + + // Converts a UTF-16 string into a local encoding. + + std::string unicodeToAnsi(const std::wstring &wstr) + { + const int len = WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, NULL, 0, NULL, NULL); + if(len == 0) + return std::string(); + + std::string str(len, '\0'); + WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, &str[0], len, NULL, NULL); + + return str; + } +} + +// If WinNT, stores a Unicode string into m_wname directly. +// If Win9x, converts and stores it into m_name to avoid calling Unicode version functions. + +FileName::FileName(const wchar_t *name) + : m_wname(IsWinNT ? name : L"") + , m_name(IsWinNT ? "" : unicodeToAnsi(name)) +{ +} + +#else + +FileName::FileName(const wchar_t *name) + : m_wname(name) +{ +} + +#endif + +FileName::FileName(const char *name) + : m_name(name) +{ +} + +FileName::FileName(const FileName &name) + : m_wname(name.m_wname) + , m_name(name.m_name) +{ +} + +FileName::operator const wchar_t *() const +{ + return m_wname.c_str(); +} + +FileName::operator const char *() const +{ + return m_name.c_str(); +} + +const std::wstring &FileName::wstr() const +{ + return m_wname; +} + +const std::string &FileName::str() const +{ + return m_name; +} + +#endif + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index d3f78c28..2cb80977 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -36,17 +36,16 @@ namespace TagLib { class TAGLIB_EXPORT FileName { public: - FileName(const wchar_t *name) : m_wname(name) {} - FileName(const char *name) : m_name(name) {} + FileName(const wchar_t *name); + FileName(const char *name); - FileName(const FileName &name) - : m_wname(name.m_wname), m_name(name.m_name) {} + FileName(const FileName &name); - operator const wchar_t *() const { return m_wname.c_str(); } - operator const char *() const { return m_name.c_str(); } + operator const wchar_t *() const; + operator const char *() const; - const std::wstring &wstr() const { return m_wname; } - const std::string &str() const { return m_name; } + const std::wstring &wstr() const; + const std::string &str() const; private: const std::string m_name; From 3293cee11e61f5e4f7f6a8a6ee8e53c988ff63a8 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 23 Apr 2013 08:38:43 +0900 Subject: [PATCH 24/33] Skip unnecessary CMake tests --- ConfigureChecks.cmake | 256 ++++++++++++++++++--------------- config-taglib.h.cmake | 3 +- taglib/toolkit/tbytevector.cpp | 16 +-- 3 files changed, 146 insertions(+), 129 deletions(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 11db70d8..67b99d88 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -11,176 +11,194 @@ include(TestBigEndian) test_big_endian(TAGLIB_BIG_ENDIAN) -if(NOT ${TAGLIB_BIG_ENDIAN}) -set(TAGLIB_LITTLE_ENDIAN 1) +if(NOT TAGLIB_BIG_ENDIAN) + set(TAGLIB_LITTLE_ENDIAN 1) endif() # Determine the size of integral types. -check_type_size("short" SIZEOF_SHORT) -check_type_size("int" SIZEOF_INT) +check_type_size("short" SIZEOF_SHORT) +check_type_size("int" SIZEOF_INT) check_type_size("long long" SIZEOF_LONGLONG) check_type_size("wchar_t" SIZEOF_WCHAR_T) # Determine if your compiler supports std::wstring. check_cxx_source_compiles(" - #include - int main() { - std::wstring x(L\"ABC\"); - return 0; - } + #include + int main() { + std::wstring x(L\"ABC\"); + return 0; + } " HAVE_STD_WSTRING) # Determine which kind of atomic operations your compiler supports. check_cxx_source_compiles(" - #include - int main() { - std::atomic x; - x.fetch_add(1); - x.fetch_sub(1); - return 0; - } + #include + int main() { + std::atomic x; + x.fetch_add(1); + x.fetch_sub(1); + return 0; + } " HAVE_STD_ATOMIC) -check_cxx_source_compiles(" - #include - int main() { - boost::atomic x(1); - x.fetch_add(1); - x.fetch_sub(1); - return 0; - } -" HAVE_BOOST_ATOMIC) +if(NOT HAVE_STD_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + boost::atomic x(1); + x.fetch_add(1); + x.fetch_sub(1); + return 0; + } + " HAVE_BOOST_ATOMIC) -check_cxx_source_compiles(" - int main() { - volatile int x; - __sync_add_and_fetch(&x, 1); - int y = __sync_sub_and_fetch(&x, 1); - return 0; - } -" HAVE_GCC_ATOMIC) + if(NOT HAVE_BOOST_ATOMIC) + check_cxx_source_compiles(" + int main() { + volatile int x; + __sync_add_and_fetch(&x, 1); + int y = __sync_sub_and_fetch(&x, 1); + return 0; + } + " HAVE_GCC_ATOMIC) -check_cxx_source_compiles(" - #include - int main() { - volatile int32_t x; - OSAtomicIncrement32Barrier(&x); - int32_t y = OSAtomicDecrement32Barrier(&x); - return 0; - } -" HAVE_MAC_ATOMIC) + if(NOT HAVE_GCC_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + volatile int32_t x; + OSAtomicIncrement32Barrier(&x); + int32_t y = OSAtomicDecrement32Barrier(&x); + return 0; + } + " HAVE_MAC_ATOMIC) -check_cxx_source_compiles(" - #include - int main() { - volatile LONG x; - InterlockedIncrement(&x); - LONG y = InterlockedDecrement(&x); - return 0; - } -" HAVE_WIN_ATOMIC) + if(NOT HAVE_MAC_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + volatile LONG x; + InterlockedIncrement(&x); + LONG y = InterlockedDecrement(&x); + return 0; + } + " HAVE_WIN_ATOMIC) -check_cxx_source_compiles(" - #include - int main() { - volatile int x; - __sync_add_and_fetch(&x, 1); - int y = __sync_sub_and_fetch(&x, 1); - return 0; - } -" HAVE_IA64_ATOMIC) + if(NOT HAVE_WIN_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + volatile int x; + __sync_add_and_fetch(&x, 1); + int y = __sync_sub_and_fetch(&x, 1); + return 0; + } + " HAVE_IA64_ATOMIC) + endif() + endif() + endif() + endif() +endif() # Determine which kind of byte swap functions your compiler supports. -# Some of them can be missing depends on the GCC version. +# GCC's __builtin_bswap* should be checked individually +# because some of them can be missing depends on the GCC version. check_cxx_source_compiles(" - int main() { - __builtin_bswap16(0); - return 0; - } + int main() { + __builtin_bswap16(0); + return 0; + } " HAVE_GCC_BYTESWAP_16) check_cxx_source_compiles(" - int main() { - __builtin_bswap32(0); - return 0; - } + int main() { + __builtin_bswap32(0); + return 0; + } " HAVE_GCC_BYTESWAP_32) check_cxx_source_compiles(" - int main() { - __builtin_bswap64(0); - return 0; - } + int main() { + __builtin_bswap64(0); + return 0; + } " HAVE_GCC_BYTESWAP_64) -check_cxx_source_compiles(" - #include - int main() { - _byteswap_ushort(0); - _byteswap_ulong(0); - _byteswap_uint64(0); - return 0; - } -" HAVE_MSC_BYTESWAP) +if(NOT HAVE_GCC_BYTESWAP_16 OR NOT HAVE_GCC_BYTESWAP_32 OR NOT HAVE_GCC_BYTESWAP_64) + check_cxx_source_compiles(" + #include + int main() { + __bswap_16(0); + __bswap_32(0); + __bswap_64(0); + return 0; + } + " HAVE_GLIBC_BYTESWAP) -check_cxx_source_compiles(" - #include - int main() { - __bswap_16(0); - __bswap_32(0); - __bswap_64(0); - return 0; - } -" HAVE_GLIBC_BYTESWAP) + if(NOT HAVE_GLIBC_BYTESWAP) + check_cxx_source_compiles(" + #include + int main() { + _byteswap_ushort(0); + _byteswap_ulong(0); + _byteswap_uint64(0); + return 0; + } + " HAVE_MSC_BYTESWAP) -check_cxx_source_compiles(" - #include - int main() { - OSSwapInt16(0); - OSSwapInt32(0); - OSSwapInt64(0); - return 0; - } -" HAVE_MAC_BYTESWAP) + if(NOT HAVE_MSC_BYTESWAP) + check_cxx_source_compiles(" + #include + int main() { + OSSwapInt16(0); + OSSwapInt32(0); + OSSwapInt64(0); + return 0; + } + " HAVE_MAC_BYTESWAP) -check_cxx_source_compiles(" - #include - int main() { - swap16(0); - swap32(0); - swap64(0); - return 0; - } -" HAVE_OPENBSD_BYTESWAP) + if(NOT HAVE_MAC_BYTESWAP) + check_cxx_source_compiles(" + #include + int main() { + swap16(0); + swap32(0); + swap64(0); + return 0; + } + " HAVE_OPENBSD_BYTESWAP) + endif() + endif() + endif() +endif() # Determine whether your compiler supports codecvt. check_cxx_source_compiles(" - #include - int main() { - std::codecvt_utf8_utf16 x; - return 0; - } + #include + int main() { + std::codecvt_utf8_utf16 x; + return 0; + } " HAVE_STD_CODECVT) # Check for libz using the cmake supplied FindZLIB.cmake find_package(ZLIB) if(ZLIB_FOUND) - set(HAVE_ZLIB 1) + set(HAVE_ZLIB 1) else() - set(HAVE_ZLIB 0) + set(HAVE_ZLIB 0) endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) - message(STATUS "CppUnit not found, disabling tests.") - set(BUILD_TESTS OFF) + message(STATUS "CppUnit not found, disabling tests.") + set(BUILD_TESTS OFF) endif() - diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index bb25bb86..aee25a79 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -25,8 +25,8 @@ #cmakedefine HAVE_GCC_BYTESWAP_16 1 #cmakedefine HAVE_GCC_BYTESWAP_32 1 #cmakedefine HAVE_GCC_BYTESWAP_64 1 -#cmakedefine HAVE_MSC_BYTESWAP 1 #cmakedefine HAVE_GLIBC_BYTESWAP 1 +#cmakedefine HAVE_MSC_BYTESWAP 1 #cmakedefine HAVE_MAC_BYTESWAP 1 #cmakedefine HAVE_OPENBSD_BYTESWAP 1 @@ -41,4 +41,3 @@ #cmakedefine WITH_MP4 1 #cmakedefine TESTS_DIR "@TESTS_DIR@" - diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index a4b12672..06f38b6e 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -222,14 +222,14 @@ ulonglong byteSwap(ulonglong x) #else - return (x & 0xff00000000000000ull) >> 56) - | (x & 0x00ff000000000000ull) >> 40) - | (x & 0x0000ff0000000000ull) >> 24) - | (x & 0x000000ff00000000ull) >> 8) - | (x & 0x00000000ff000000ull) << 8) - | (x & 0x0000000000ff0000ull) << 24) - | (x & 0x000000000000ff00ull) << 40) - | (x & 0x00000000000000ffull) << 56); + return ((x & 0xff00000000000000ull) >> 56) + | ((x & 0x00ff000000000000ull) >> 40) + | ((x & 0x0000ff0000000000ull) >> 24) + | ((x & 0x000000ff00000000ull) >> 8) + | ((x & 0x00000000ff000000ull) << 8) + | ((x & 0x0000000000ff0000ull) << 24) + | ((x & 0x000000000000ff00ull) << 40) + | ((x & 0x00000000000000ffull) << 56); #endif } From 2c85b4d178d98a2dd3e4c44d4ea95c1234619f50 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 23 Apr 2013 10:42:45 +0900 Subject: [PATCH 25/33] Fix mistaken preprocessor conditionals --- taglib/toolkit/taglib.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index 81d23f04..833f624b 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -117,7 +117,7 @@ # include #endif -#if defined(HAVE_GCC_BYTESWAP16) +#if defined(HAVE_GCC_BYTESWAP_16) # define TAGLIB_BYTESWAP_16(x) __builtin_bswap16(x) #elif defined(HAVE_MSC_BYTESWAP) # define TAGLIB_BYTESWAP_16(x) _byteswap_ushort(x) @@ -129,7 +129,7 @@ # define TAGLIB_BYTESWAP_16(x) swap16(x) #endif -#if defined(HAVE_GCC_BYTESWAP32) +#if defined(HAVE_GCC_BYTESWAP_32) # define TAGLIB_BYTESWAP_32(x) __builtin_bswap32(x) #elif defined(HAVE_MSC_BYTESWAP) # define TAGLIB_BYTESWAP_32(x) _byteswap_ulong(x) @@ -141,7 +141,7 @@ # define TAGLIB_BYTESWAP_32(x) swap32(x) #endif -#if defined(HAVE_GCC_BYTESWAP64) +#if defined(HAVE_GCC_BYTESWAP_64) # define TAGLIB_BYTESWAP_64(x) __builtin_bswap64(x) #elif defined(HAVE_MSC_BYTESWAP) # define TAGLIB_BYTESWAP_64(x) _byteswap_uint64(x) From 8c71428d4f99bae21f227c7498f2c81dbb0cf40e Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 23 Apr 2013 16:25:18 +0900 Subject: [PATCH 26/33] Add missing HAVE_WIN_ATOMIC block --- taglib/toolkit/taglib.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index 833f624b..bc94aa88 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -69,38 +69,38 @@ #if defined(HAVE_STD_ATOMIC) # include -#elif defined(HAVE_BOOST_ATOMIC) -# include -#elif defined(HAVE_MAC_ATOMIC) -# include -#elif defined(HAVE_WIN_ATOMIC) -# include -#elif defined(HAVE_IA64_ATOMIC) -# include -#endif - -#if defined(HAVE_STD_ATOMIC) # define TAGLIB_ATOMIC_INT std::atomic # define TAGLIB_ATOMIC_INC(x) x.fetch_add(1) # define TAGLIB_ATOMIC_DEC(x) (x.fetch_sub(1) - 1) #elif defined(HAVE_BOOST_ATOMIC) +# include # define TAGLIB_ATOMIC_INT boost::atomic # define TAGLIB_ATOMIC_INC(x) x.fetch_add(1) # define TAGLIB_ATOMIC_DEC(x) (x.fetch_sub(1) - 1) #elif defined(HAVE_GCC_ATOMIC) -# define TAGLIB_ATOMIC_INT volatile int +# define TAGLIB_ATOMIC_INT int # define TAGLIB_ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) # define TAGLIB_ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +#elif defined(HAVE_WIN_ATOMIC) +# if !defined(NOMINMAX) +# define NOMINMAX +# endif +# include +# define TAGLIB_ATOMIC_INT long +# define TAGLIB_ATOMIC_INC(x) InterlockedIncrement(&x) +# define TAGLIB_ATOMIC_DEC(x) InterlockedDecrement(&x) #elif defined(HAVE_MAC_ATOMIC) -# define TAGLIB_ATOMIC_INT volatile int32_t +# include +# define TAGLIB_ATOMIC_INT int32_t # define TAGLIB_ATOMIC_INC(x) OSAtomicIncrement32Barrier(&x) # define TAGLIB_ATOMIC_DEC(x) OSAtomicDecrement32Barrier(&x) #elif defined(HAVE_IA64_ATOMIC) -# define TAGLIB_ATOMIC_INT volatile int +# include +# define TAGLIB_ATOMIC_INT int # define TAGLIB_ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) # define TAGLIB_ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) #else -# define TAGLIB_ATOMIC_INT volatile int +# define TAGLIB_ATOMIC_INT int # define TAGLIB_ATOMIC_INC(x) (++x) # define TAGLIB_ATOMIC_DEC(x) (--x) #endif @@ -204,7 +204,7 @@ namespace TagLib { int count() { return refCount; } private: - TAGLIB_ATOMIC_INT refCount; + volatile TAGLIB_ATOMIC_INT refCount; }; #endif // DO_NOT_DOCUMENT From 6e35e56d7f39906d9ffaf84e001659d03fe71440 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Fri, 26 Apr 2013 17:32:39 +0900 Subject: [PATCH 27/33] Small bug fix in tstring.cpp --- taglib/toolkit/tstring.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 72f4a24a..eeba15af 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -709,7 +709,7 @@ String &String::operator=(wchar_t c) if(d->deref()) delete d; - d = new StringPrivate(1, static_cast(c)); + d = new StringPrivate(1, c); return *this; } From 5e13e0c838ec7d79a8e7f74d647b344c5b4e17c8 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Fri, 26 Apr 2013 19:43:10 +0900 Subject: [PATCH 28/33] Add some tests for String --- tests/test_string.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_string.cpp b/tests/test_string.cpp index 4a58c277..f2976919 100644 --- a/tests/test_string.cpp +++ b/tests/test_string.cpp @@ -62,6 +62,13 @@ public: String latin = "Jos\xe9 Carlos"; CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0); + String c; + c = "1"; + CPPUNIT_ASSERT(c == L"1"); + + c = L'\u4E00'; + CPPUNIT_ASSERT(c == L"\u4E00"); + String unicode2(unicode.to8Bit(true), String::UTF8); CPPUNIT_ASSERT(unicode == unicode2); From f3cbb883f2a7611c7f9a3847aeba3c16dd4276f9 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 28 Apr 2013 02:57:51 +0900 Subject: [PATCH 29/33] Fixed detection of alignment-tolerant CPUs --- taglib/toolkit/tstring.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index eeba15af..392f32ed 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -32,6 +32,12 @@ #include #include +// x86 CPUs are alignment-tolerant or allow pointer casts from smaller types to larger types. +#if defined(__i386__) || defined(_M_IX86) || defined(__amd64) || defined(__amd64__) \ + || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) +# define TAGLIB_ALIGNMENT_TOLERANT 1 +#endif + #ifdef HAVE_STD_CODECVT # include #else @@ -805,16 +811,12 @@ void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) void String::copyFromUTF16(const char *s, size_t length, Type t) { -#if !defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) - - // It's certain that sizeof(wchar_t) == 2 and alignment-tolerant. +#if SIZEOF_WCHAR_T == 2 && defined(TAGLIB_ALIGNMENT_TOLERANT) copyFromUTF16(reinterpret_cast(s), length / 2, t); #else - // Maybe sizeof(wchar_t) != 2 or alignment-strict. - bool swap; if(t == UTF16) { if(length < 2) { From d2273a721888879b6a5c7cd7d60f473bdae28384 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 28 Apr 2013 03:06:59 +0900 Subject: [PATCH 30/33] Comment update --- taglib/riff/wav/infotag.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/taglib/riff/wav/infotag.h b/taglib/riff/wav/infotag.h index 72414841..3210b555 100644 --- a/taglib/riff/wav/infotag.h +++ b/taglib/riff/wav/infotag.h @@ -1,6 +1,6 @@ /*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org + copyright : (C) 2012 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** @@ -82,7 +82,7 @@ namespace TagLib { * This is the main class in the INFO tag implementation. RIFF INFO tag is a * metadata format found in WAV audio and AVI video files. Though it is a part * of Microsoft/IBM's RIFF specification, the author could not find the official - * documents about it. So, this implementation is refering to unofficial documents + * documents about it. So, this implementation is referring to unofficial documents * online and some applications' behaviors especially Windows Explorer. */ class TAGLIB_EXPORT Tag : public TagLib::Tag From 395743eb49493a97d99c7c9d59be402c9c1285fd Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 28 Apr 2013 09:14:37 +0900 Subject: [PATCH 31/33] Add some error handling to tfilestream.cpp --- taglib/toolkit/tfilestream.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index a8de32aa..2ce5ab41 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -426,6 +426,9 @@ void FileStream::seek(long offset, Position p) } SetFilePointer(d->file, offset, NULL, whence); + if(GetLastError() != NO_ERROR) { + debug("File::seek() -- Failed to set the file size."); + } #else @@ -467,7 +470,14 @@ long FileStream::tell() const { #ifdef _WIN32 - return (long)SetFilePointer(d->file, 0, NULL, FILE_CURRENT); + const DWORD position = SetFilePointer(d->file, 0, NULL, FILE_CURRENT); + if(GetLastError() == NO_ERROR) { + return static_cast(position); + } + else { + debug("File::tell() -- Failed to get the file pointer."); + return 0; + } #else @@ -491,7 +501,7 @@ long FileStream::length() #ifdef _WIN32 const DWORD fileSize = GetFileSize(d->file, NULL); - if(GetLastError() != ERROR_SUCCESS) { + if(GetLastError() == NO_ERROR) { d->size = static_cast(fileSize); return d->size; } @@ -528,6 +538,9 @@ void FileStream::truncate(long length) seek(length); SetEndOfFile(d->file); + if(GetLastError() != NO_ERROR) { + debug("File::truncate() -- Failed to truncate the file."); + } seek(currentPos); From 289b6abb43565185a342a2d6b0a3cfea9a977be0 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Mon, 29 Apr 2013 23:56:07 +0300 Subject: [PATCH 32/33] Correctly initialize std::mbstate_t. mbstate_t is an opaque type that is often a union or a struct, so setting it directly to 0 is incorrect and causes build failures with some compilers such as clang. --- taglib/toolkit/tstring.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 392f32ed..eaf5291e 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -78,9 +78,10 @@ namespace char *dstBegin = dst; char *dstEnd = dstBegin + dstLength; - std::mbstate_t st = 0; + std::mbstate_t st; const wchar_t *source; char *target; + memset(&st, 0, sizeof(st)); std::codecvt_base::result result = utf8_utf16_t().out( st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); @@ -123,9 +124,10 @@ namespace wchar_t *dstBegin = dst; wchar_t *dstEnd = dstBegin + dstLength; - std::mbstate_t st = 0; + std::mbstate_t st; const char *source; wchar_t *target; + memset(&st, 0, sizeof(st)); std::codecvt_base::result result = utf8_utf16_t().in( st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); From d6fc2ef4aac0c921633b353e3a1a7e0d636b6e83 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Wed, 1 May 2013 01:32:48 +0900 Subject: [PATCH 33/33] Fixed possible memory leak --- taglib/riff/wav/infotag.cpp | 13 ++++++++----- taglib/riff/wav/infotag.h | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index 5ce1df90..658ede88 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler + copyright : (C) 2012 by Tsuda Kageyu email : wheeler@kde.org ***************************************************************************/ @@ -86,19 +86,22 @@ ByteVector RIFF::Info::StringHandler::render(const String &s) const static const StringHandler defaultStringHandler; const RIFF::Info::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler; -RIFF::Info::Tag::Tag(const ByteVector &data) : TagLib::Tag() +RIFF::Info::Tag::Tag(const ByteVector &data) + : TagLib::Tag() + , d(new TagPrivate()) { - d = new TagPrivate; parse(data); } -RIFF::Info::Tag::Tag() : TagLib::Tag() +RIFF::Info::Tag::Tag() + : TagLib::Tag() + , d(new TagPrivate()) { - d = new TagPrivate; } RIFF::Info::Tag::~Tag() { + delete d; } String RIFF::Info::Tag::title() const diff --git a/taglib/riff/wav/infotag.h b/taglib/riff/wav/infotag.h index 3210b555..9a26d4cb 100644 --- a/taglib/riff/wav/infotag.h +++ b/taglib/riff/wav/infotag.h @@ -119,6 +119,7 @@ namespace TagLib { virtual void setTrack(uint i); virtual bool isEmpty() const; + /* * Gets the value of the field with the ID \a id. */ @@ -129,7 +130,7 @@ namespace TagLib { * If the field does not exist, it is created. * If \s is empty, the field is removed. * - * \note fieldId must be four-byte long pure ascii string. This function + * \note fieldId must be four-byte long pure ASCII string. This function * performs nothing if fieldId is invalid. */ void setFieldText(const ByteVector &id, const String &s);