From f9efcfb8d6445fbc40480c0f482e554e7c4f787e Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Thu, 16 May 2013 20:26:20 +0900 Subject: [PATCH 01/10] Fixed the test for ID3V2's compressed frame --- tests/test_id3v2.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 48faf306..42d0f138 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -1,5 +1,6 @@ #include #include +#include // so evil :( #define protected public #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -580,13 +582,27 @@ public: { MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false); CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC")); - ID3v2::AttachedPictureFrame *frame = - static_cast(f.ID3v2Tag()->frameListMap()["APIC"].front()); + +#ifdef HAVE_ZLIB + + ID3v2::AttachedPictureFrame *frame + = dynamic_cast(f.ID3v2Tag()->frameListMap()["APIC"].front()); CPPUNIT_ASSERT(frame); CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type()); CPPUNIT_ASSERT_EQUAL(String(""), frame->description()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(86414), frame->picture().size()); + +#else + + // Skip the test if ZLIB is not installed. + // The message "Compressed frames are currently not supported." will be displayed. + + ID3v2::UnknownFrame *frame + = dynamic_cast(f.ID3v2Tag()->frameListMap()["APIC"].front()); + CPPUNIT_ASSERT(frame); + +#endif } void testW000() From 5ed8d12478f74e034bee90822f25a29e6e3cc722 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sat, 18 May 2013 13:45:44 +0900 Subject: [PATCH 02/10] Redefined smart pointer classes in safer way --- ConfigureChecks.cmake | 16 +- taglib/CMakeLists.txt | 3 +- taglib/asf/asfattribute.h | 2 +- taglib/asf/asfpicture.h | 2 +- taglib/fileref.cpp | 2 +- taglib/fileref.h | 2 +- taglib/mp4/mp4coverart.h | 2 +- taglib/mp4/mp4item.h | 2 +- taglib/mpeg/mpegheader.h | 2 +- taglib/riff/aiff/aiffproperties.h | 2 +- taglib/taglib_config.h.cmake | 10 +- taglib/tagunion.cpp | 4 +- taglib/tagunion.h | 2 +- taglib/toolkit/tbytevector.cpp | 4 +- taglib/toolkit/tbytevector.h | 2 +- taglib/toolkit/tlist.h | 2 +- taglib/toolkit/tmap.h | 2 +- taglib/toolkit/trefcountptr.h | 273 -------- .../{trefcountptr.cpp => tsmartptr.cpp} | 45 +- taglib/toolkit/tsmartptr.h | 583 +++++++++++++++++- taglib/toolkit/tstring.h | 2 +- tests/test_smartptr.cpp | 24 +- 22 files changed, 645 insertions(+), 343 deletions(-) delete mode 100644 taglib/toolkit/trefcountptr.h rename taglib/toolkit/{trefcountptr.cpp => tsmartptr.cpp} (82%) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 134d584e..3746e6d8 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -213,7 +213,7 @@ check_cxx_source_compiles(" check_cxx_source_compiles(" #include - int main() { std::tr1::shared_ptr x; return 0; } + int main() { std::shared_ptr x; return 0; } " TAGLIB_USE_STD_SHARED_PTR) if(NOT TAGLIB_USE_STD_SHARED_PTR) @@ -230,6 +230,20 @@ if(NOT TAGLIB_USE_STD_SHARED_PTR) endif() endif() +# Determine where unique_ptr or scoped_ptr is defined regardless of C++11 support. + +check_cxx_source_compiles(" + #include + int main() { std::unique_ptr x; return 0; } +" TAGLIB_USE_STD_UNIQUE_PTR) + +if(NOT TAGLIB_USE_STD_UNIQUE_PTR) + check_cxx_source_compiles(" + #include + int main() { boost::scoped_ptr x; return 0; } + " TAGLIB_USE_BOOST_SCOPED_PTR) +endif() + # Determine whether CppUnit is installed. set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index 56d4d15e..1b406ebd 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -54,7 +54,6 @@ set(tag_HDRS toolkit/tmap.tcc toolkit/tpropertymap.h toolkit/tsmartptr.h - toolkit/trefcountptr.h mpeg/mpegfile.h mpeg/mpegproperties.h mpeg/mpegheader.h @@ -301,7 +300,7 @@ set(toolkit_SRCS toolkit/tfilestream.cpp toolkit/tdebug.cpp toolkit/tpropertymap.cpp - toolkit/trefcountptr.cpp + toolkit/tsmartptr.cpp toolkit/unicode.cpp ) diff --git a/taglib/asf/asfattribute.h b/taglib/asf/asfattribute.h index 9740cb18..18269da4 100644 --- a/taglib/asf/asfattribute.h +++ b/taglib/asf/asfattribute.h @@ -205,7 +205,7 @@ namespace TagLib ByteVector render(const String &name, int kind = 0) const; class AttributePrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; } diff --git a/taglib/asf/asfpicture.h b/taglib/asf/asfpicture.h index 5f688898..463bd43d 100644 --- a/taglib/asf/asfpicture.h +++ b/taglib/asf/asfpicture.h @@ -231,7 +231,7 @@ namespace TagLib #endif private: class PicturePrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; } } diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index f923f3ad..f24f4c56 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -64,7 +64,7 @@ class FileRef::FileRefPrivate public: FileRefPrivate(File *f) : file(f) {} - TAGLIB_SHARED_PTR file; + RefCountPtr file; static List fileTypeResolvers; }; diff --git a/taglib/fileref.h b/taglib/fileref.h index f11e3d5d..c323b086 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -282,7 +282,7 @@ namespace TagLib { private: class FileRefPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; } // namespace TagLib diff --git a/taglib/mp4/mp4coverart.h b/taglib/mp4/mp4coverart.h index e2b82c79..ea9784ad 100644 --- a/taglib/mp4/mp4coverart.h +++ b/taglib/mp4/mp4coverart.h @@ -66,7 +66,7 @@ namespace TagLib { private: class CoverArtPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; typedef List CoverArtList; diff --git a/taglib/mp4/mp4item.h b/taglib/mp4/mp4item.h index 91fd4c15..8ad23cf1 100644 --- a/taglib/mp4/mp4item.h +++ b/taglib/mp4/mp4item.h @@ -97,7 +97,7 @@ namespace TagLib { private: class ItemPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; } diff --git a/taglib/mpeg/mpegheader.h b/taglib/mpeg/mpegheader.h index 56749465..0e168df1 100644 --- a/taglib/mpeg/mpegheader.h +++ b/taglib/mpeg/mpegheader.h @@ -181,7 +181,7 @@ namespace TagLib { void parse(const ByteVector &data); class HeaderPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; } } diff --git a/taglib/riff/aiff/aiffproperties.h b/taglib/riff/aiff/aiffproperties.h index 903ea290..8cb78c49 100644 --- a/taglib/riff/aiff/aiffproperties.h +++ b/taglib/riff/aiff/aiffproperties.h @@ -73,7 +73,7 @@ namespace TagLib { void read(const ByteVector &data); class PropertiesPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; } } diff --git a/taglib/taglib_config.h.cmake b/taglib/taglib_config.h.cmake index 036f2cfd..4f2045d1 100644 --- a/taglib/taglib_config.h.cmake +++ b/taglib/taglib_config.h.cmake @@ -7,7 +7,11 @@ #cmakedefine TAGLIB_USE_MOVE_SEMANTICS 1 /* Defined if your compiler supports shared_ptr */ -#cmakedefine TAGLIB_USE_STD_SHARED_PTR 1 -#cmakedefine TAGLIB_USE_TR1_SHARED_PTR 1 -#cmakedefine TAGLIB_USE_BOOST_SHARED_PTR 1 +#cmakedefine TAGLIB_USE_STD_SHARED_PTR 1 // #include / std::shared_ptr +#cmakedefine TAGLIB_USE_TR1_SHARED_PTR 1 // #include / std::tr1::shared_ptr +#cmakedefine TAGLIB_USE_BOOST_SHARED_PTR 1 // #include / boost::shared_ptr + +/* Defined if your compiler supports unique_ptr or scoped_ptr */ +#cmakedefine TAGLIB_USE_STD_UNIQUE_PTR 1 // #include / std::unique_ptr +#cmakedefine TAGLIB_USE_BOOST_SCOPED_PTR 1 // #include / boost::scoped_ptr diff --git a/taglib/tagunion.cpp b/taglib/tagunion.cpp index cb45d692..fe7631d0 100644 --- a/taglib/tagunion.cpp +++ b/taglib/tagunion.cpp @@ -31,7 +31,7 @@ using namespace TagLib; namespace { - typedef std::vector > TagVector; + typedef std::vector > TagVector; typedef TagVector::iterator TagIterator; typedef TagVector::const_iterator TagConstIterator; } @@ -66,7 +66,7 @@ public: { } - std::vector > tags; + TagVector tags; }; TagUnion::TagUnion(size_t count) diff --git a/taglib/tagunion.h b/taglib/tagunion.h index 39c3e2af..5479e71a 100644 --- a/taglib/tagunion.h +++ b/taglib/tagunion.h @@ -89,7 +89,7 @@ namespace TagLib { TagUnion &operator=(const Tag &); class TagUnionPrivate; - TAGLIB_SHARED_PTR d; + NonRefCountPtr d; }; } diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 19e2c8f4..d7111bda 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -363,7 +363,7 @@ public: { } - ByteVectorPrivate(TAGLIB_SHARED_PTR d, size_t o, size_t l) + ByteVectorPrivate(RefCountPtr d, size_t o, size_t l) : data(d->data) , offset(d->offset + o) , length(l) @@ -411,7 +411,7 @@ public: return *this; } - TAGLIB_SHARED_PTR > data; + RefCountPtr > data; size_t offset; size_t length; }; diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index 613f4306..ae3039a7 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -551,7 +551,7 @@ namespace TagLib { private: class ByteVectorPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; /*! diff --git a/taglib/toolkit/tlist.h b/taglib/toolkit/tlist.h index 51338748..dcd95b0c 100644 --- a/taglib/toolkit/tlist.h +++ b/taglib/toolkit/tlist.h @@ -305,7 +305,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class ListPrivate; - TAGLIB_SHARED_PTR > d; + RefCountPtr > d; #endif }; diff --git a/taglib/toolkit/tmap.h b/taglib/toolkit/tmap.h index 46d82f99..f291226f 100644 --- a/taglib/toolkit/tmap.h +++ b/taglib/toolkit/tmap.h @@ -219,7 +219,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class MapPrivate; - TAGLIB_SHARED_PTR > d; + RefCountPtr > d; #endif }; diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h deleted file mode 100644 index a1c578b4..00000000 --- a/taglib/toolkit/trefcountptr.h +++ /dev/null @@ -1,273 +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 - -#include - -#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 { - -#if defined(TAGLIB_USE_STD_SHARED_PTR) || defined(TAGLIB_USE_TR1_SHARED_PTR) - -#define TAGLIB_SHARED_PTR std::tr1::shared_ptr - -#elif defined(TAGLIB_USE_BOOST_SHARED_PTR) - -#define TAGLIB_SHARED_PTR boost::shared_ptr - -#else // TAGLIB_USE_*_SHARED_PTR - - // Self-implements RefCountPtr if shared_ptr is not available. - // I STRONGLY RECOMMEND using standard shared_ptr rather than this class. - - class RefCounter - { - public: - RefCounter(); - ~RefCounter(); - - size_t ref(); - size_t deref(); - size_t count() const; - - private: - class RefCounterPrivate; - RefCounterPrivate *d; - }; - - template - class RefCountPtr - { - private: - - // Counter base class. Provides a reference counter. - - class CounterBase - { - public: - virtual ~CounterBase() - { - } - - void addref() - { - count.ref(); - } - - void release() - { - if(count.deref() == 0) { - dispose(); - delete this; - } - } - - long use_count() const - { - return static_cast(count.count()); - } - - virtual void dispose() = 0; - - private: - RefCounter 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: - explicit RefCountPtr() - : counter(0) - { - } - - template - explicit RefCountPtr(U *p) - : counter(new CounterImpl(p)) - { - } - - RefCountPtr(const RefCountPtr &x) - : counter(x.counter) - { - if(counter) - counter->addref(); - } - - template - RefCountPtr(const RefCountPtr &x) - : counter(reinterpret_cast(x.counter)) - { - if(counter) - counter->addref(); - } - - ~RefCountPtr() - { - if(counter) - counter->release(); - } - - T *get() const - { - if(counter) - return static_cast*>(counter)->get(); - else - return 0; - } - - long use_count() const - { - if(counter) - return counter->use_count(); - else - return 0; - } - - bool unique() const - { - return (use_count() == 1); - } - - template - void reset(U *p) - { - if(get() != p) - RefCountPtr(p).swap(*this); - } - - void reset() - { - RefCountPtr().swap(*this); - } - - void swap(RefCountPtr &x) - { - std::swap(counter, x.counter); - } - - RefCountPtr &operator=(const RefCountPtr &x) - { - if(get() != x.get()) { - if(counter) - counter->release(); - - counter = x.counter; - - if(counter) - counter->addref(); - } - return *this; - } - - template - RefCountPtr &operator=(const RefCountPtr &x) - { - if(get() != x.get()) { - if(counter) - counter->release(); - - counter = reinterpret_cast(x.counter); - - if(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: - mutable CounterBase *counter; - - template friend class RefCountPtr; - }; - - template - void swap(RefCountPtr &a, RefCountPtr &b) - { - a.swap(b); - } - -#endif // TAGLIB_USE_*_SHARED_PTR -} -#endif // DO_NOT_DOCUMENT - -#endif diff --git a/taglib/toolkit/trefcountptr.cpp b/taglib/toolkit/tsmartptr.cpp similarity index 82% rename from taglib/toolkit/trefcountptr.cpp rename to taglib/toolkit/tsmartptr.cpp index cfd469a5..87ad6ee3 100644 --- a/taglib/toolkit/trefcountptr.cpp +++ b/taglib/toolkit/tsmartptr.cpp @@ -23,8 +23,14 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include "taglib_config.h" + +#if !defined(TAGLIB_USE_STD_SHARED_PTR) \ + && !defined(TAGLIB_USE_TR1_SHARED_PTR) \ + && !defined(TAGLIB_USE_BOOST_SHARED_PTR) + #include "config.h" -#include "trefcountptr.h" +#include "tsmartptr.h" #if defined(HAVE_STD_ATOMIC) # include @@ -66,41 +72,44 @@ namespace TagLib { - class RefCounter::RefCounterPrivate + class CounterBase::CounterBasePrivate { public: - RefCounterPrivate() : refCount(1) {} - - size_t ref() { return static_cast(ATOMIC_INC(refCount)); } - size_t deref() { return static_cast(ATOMIC_DEC(refCount)); } - size_t count() const { return static_cast(refCount); } + CounterBasePrivate() + : refCount(1) + { + } volatile ATOMIC_INT refCount; }; - RefCounter::RefCounter() - : d(new RefCounterPrivate()) + CounterBase::CounterBase() + : d(new CounterBasePrivate()) { } - RefCounter::~RefCounter() + CounterBase::~CounterBase() { delete d; } - size_t RefCounter::ref() + void CounterBase::addref() { - return d->ref(); + ATOMIC_INC(d->refCount); } - size_t RefCounter::deref() - { - return d->deref(); + void CounterBase::release() + { + if(ATOMIC_DEC(d->refCount) == 0) { + dispose(); + delete this; + } } - size_t RefCounter::count() const - { - return d->count(); + long CounterBase::use_count() const + { + return static_cast(d->refCount); } } +#endif diff --git a/taglib/toolkit/tsmartptr.h b/taglib/toolkit/tsmartptr.h index a86749d3..c3532195 100644 --- a/taglib/toolkit/tsmartptr.h +++ b/taglib/toolkit/tsmartptr.h @@ -27,28 +27,577 @@ #define TAGLIB_SMARTPTR_H #include "taglib_config.h" +#include #if defined(TAGLIB_USE_STD_SHARED_PTR) # include #elif defined(TAGLIB_USE_TR1_SHARED_PTR) # include -#elif defined(TAGLIB_USE_BOOST_SHARED_PTR) -# include -#else -# include "trefcountptr.h" -#endif - -#if defined(TAGLIB_USE_STD_SHARED_PTR) || defined(TAGLIB_USE_TR1_SHARED_PTR) - -# define TAGLIB_SHARED_PTR std::tr1::shared_ptr - #elif defined(TAGLIB_USE_BOOST_SHARED_PTR) - -# define TAGLIB_SHARED_PTR boost::shared_ptr - -#else - -# define TAGLIB_SHARED_PTR TagLib::RefCountPtr - +# include #endif + +#if defined(TAGLIB_USE_STD_UNIQUE_PTR) +# include +#elif defined(TAGLIB_USE_BOOST_SCOPED_PTR) +# include +#endif + +#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. +/*! + * \warning This is not part of the TagLib public API! + */ + +namespace TagLib +{ +#if defined(TAGLIB_USE_STD_SHARED_PTR) \ + || defined(TAGLIB_USE_TR1_SHARED_PTR) \ + || defined(TAGLIB_USE_BOOST_SHARED_PTR) + + // RefCountPtr is just a thin wrapper of shared_ptr. + // It will be optimized out by compilers and performs equivalent to them. + + template + class RefCountPtr + { + public: + RefCountPtr() + : sp() + { + } + + template + explicit RefCountPtr(U *p) + : sp(p) + { + } + + RefCountPtr(const RefCountPtr &x) + : sp(x.sp) + { + } + + template + RefCountPtr(const RefCountPtr &x) + : sp(x.sp) + { + } + +# ifdef TAGLIB_USE_MOVE_SEMANTICS + + RefCountPtr(RefCountPtr &&x) + : sp(std::move(x.sp)) + { + } + + template + RefCountPtr(RefCountPtr &&x) + : sp(std::move(x.sp)) + { + } + +# endif + + T *get() const + { + return sp.get(); + } + + long use_count() const + { + return sp.use_count(); + } + + bool unique() const + { + return sp.unique(); + } + + template + void reset(U *p) + { + sp.reset(p); + } + + void reset() + { + sp.reset(); + } + + void swap(RefCountPtr &x) + { + sp.swap(x.sp); + } + + RefCountPtr &operator=(const RefCountPtr &x) + { + sp = x.sp; + return *this; + } + + template + RefCountPtr &operator=(const RefCountPtr &x) + { + sp = x.sp; + return *this; + } + +# ifdef TAGLIB_USE_MOVE_SEMANTICS + + RefCountPtr &operator=(RefCountPtr &&x) + { + sp = std::move(x.sp); + return *this; + } + + template + RefCountPtr &operator=(RefCountPtr &&x) + { + sp = std::move(x.sp); + return *this; + } + +# endif + + T& operator*() const + { + return sp.operator*(); + } + + T* operator->() const + { + return sp.operator->(); + } + + operator bool() const + { + return static_cast(sp); + } + + bool operator!() const + { + return !static_cast(sp); + } + + private: + template friend class RefCountPtr; + +# if defined(TAGLIB_USE_STD_SHARED_PTR) + + std::shared_ptr sp; + +# elif defined(TAGLIB_USE_TR1_SHARED_PTR) + + std::tr1::shared_ptr sp; + +# else + + boost::shared_ptr sp; + +# endif + }; + +#else // TAGLIB_USE_STD_SHARED_PTR etc. + + // Self-implements RefCountPtr if shared_ptr is not available. + // I STRONGLY RECOMMEND using standard shared_ptr rather than this class. + + // Counter base class. Provides a reference counter. + + class CounterBase + { + public: + CounterBase(); + virtual ~CounterBase(); + + void addref(); + void release(); + long use_count() const; + + virtual void dispose() = 0; + + private: + class CounterBasePrivate; + CounterBasePrivate *d; + }; + + // Counter impl class. Provides a dynamic deleter. + + template + class CounterImpl : public CounterBase + { + public: + CounterImpl(T *p) + : p(p) + { + } + + virtual void dispose() + { + delete p; + } + + T *get() const + { + return p; + } + + private: + T *p; + }; + + template + class RefCountPtr + { + public: + RefCountPtr() + : px(0) + , counter(0) + { + } + + template + explicit RefCountPtr(U *p) + : px(p) + , counter(new CounterImpl(p)) + { + } + + RefCountPtr(const RefCountPtr &x) + : px(x.px) + , counter(x.counter) + { + if(counter) + counter->addref(); + } + + template + RefCountPtr(const RefCountPtr &x) + : px(x.px) + , counter(x.counter) + { + if(counter) + counter->addref(); + } + + ~RefCountPtr() + { + if(counter) + counter->release(); + } + + T *get() const + { + return px; + } + + long use_count() const + { + if(counter) + return counter->use_count(); + else + return 0; + } + + bool unique() const + { + return (use_count() == 1); + } + + template + void reset(U *p) + { + if(px != p) + RefCountPtr(p).swap(*this); + } + + void reset() + { + RefCountPtr().swap(*this); + } + + void swap(RefCountPtr &x) + { + std::swap(px, x.px); + std::swap(counter, x.counter); + } + + RefCountPtr &operator=(const RefCountPtr &x) + { + if(px != x.px) { + if(counter) + counter->release(); + + px = x.px; + counter = x.counter; + + if(counter) + counter->addref(); + } + return *this; + } + + template + RefCountPtr &operator=(const RefCountPtr &x) + { + if(px != x.px) { + if(counter) + counter->release(); + + px = x.px; + counter = x.counter; + + if(counter) + counter->addref(); + } + return *this; + } + + T& operator*() const + { + return *px; + } + + T* operator->() const + { + return px; + } + + operator bool() const + { + return (px != 0); + } + + bool operator!() const + { + return (px == 0); + } + + private: + T *px; + CounterBase *counter; + + template friend class RefCountPtr; + }; + +#endif // TAGLIB_USE_STD_SHARED_PTR etc. + +#if defined(TAGLIB_USE_STD_UNIQUE_PTR) || defined(TAGLIB_USE_BOOST_SCOPED_PTR) + + // NonRefCountPtr is just a thin wrapper of unique_ptr or scoped_ptr. + // It will be optimized out by compilers and performs equivalent to them. + + template + class NonRefCountPtr + { + public: + explicit NonRefCountPtr(T *p = 0) + : up(p) + { + } + + ~NonRefCountPtr() + { + } + + void reset(T *p = 0) + { + NonRefCountPtr(p).swap(*this); + } + + T &operator*() const + { + return up.operator*(); + } + + T *operator->() const + { + return up.operator->(); + } + + T *get() const + { + return up.get(); + } + + operator bool() const + { + return static_cast(up); + } + + bool operator!() const + { + return !static_cast(up); + } + + void swap(NonRefCountPtr &x) + { + up.swap(x.up); + } + + private: + + // Noncopyable + NonRefCountPtr(const NonRefCountPtr &); + NonRefCountPtr &operator=(const NonRefCountPtr &); + + void operator==(const NonRefCountPtr &) const; + void operator!=(const NonRefCountPtr &) const; + +# if defined(TAGLIB_USE_STD_UNIQUE_PTR) + + std::unique_ptr up; + +# else + + boost::scoped_ptr up; + +# endif + }; + +#else // TAGLIB_USE_STD_UNIQUE_PTR + + // Self-implements NonRefCountPtr if unique_ptr is not available. + // I STRONGLY RECOMMEND using standard unique_ptr rather than this class. + + template + class NonRefCountPtr + { + public: + explicit NonRefCountPtr(T *p = 0) + : px(p) + { + } + + ~NonRefCountPtr() + { + delete px; + } + + void reset(T *p = 0) + { + NonRefCountPtr(p).swap(*this); + } + + T &operator*() const + { + return *px; + } + + T *operator->() const + { + return px; + } + + T *get() const + { + return px; + } + + operator bool() const + { + return (px != 0); + } + + bool operator!() const + { + return (px == 0); + } + + + void swap(NonRefCountPtr &x) + { + std::swap(px, x.px); + } + + private: + + // Noncopyable + NonRefCountPtr(const NonRefCountPtr &); + NonRefCountPtr &operator=(const NonRefCountPtr &); + + void operator==(const NonRefCountPtr &) const; + void operator!=(const NonRefCountPtr &) const; + + T *px; + }; + +#endif // TAGLIB_USE_STD_UNIQUE_PTR + + // Comparison operators for smart pointers. + + template + bool operator==(const RefCountPtr &a, const RefCountPtr &b) + { + return (a.get() == b.get()); + } + + template + bool operator!=(const RefCountPtr &a, const RefCountPtr &b) + { + return (a.get() != b.get()); + } + + template + bool operator==(const RefCountPtr &a, U *b) + { + return (a.get() == b); + } + + template + bool operator!=(const RefCountPtr &a, U *b) + { + return (a.get() != b); + } + + template + bool operator==(const NonRefCountPtr &a, U *b) + { + return (a.get() == b); + } + + template + bool operator!=(const NonRefCountPtr &a, U *b) + { + return (a.get() != b); + } + + template + bool operator==(T *a, const RefCountPtr &b) + { + return (a == b.get()); + } + + template + bool operator!=(T *a, const RefCountPtr &b) + { + return (a != b.get()); + } + + template + bool operator==(T *a, const NonRefCountPtr &b) + { + return (a == b.get()); + } + + template + bool operator!=(T *a, const NonRefCountPtr &b) + { + return (a != b.get()); + } + + template + void swap(RefCountPtr &a, RefCountPtr &b) + { + a.swap(b); + } + + template + void swap(NonRefCountPtr &a, NonRefCountPtr &b) + { + a.swap(b); + } +} + +#endif // DO_NOT_DOCUMENT #endif diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index d599107d..3da8814b 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -520,7 +520,7 @@ namespace TagLib { static const Type WCharByteOrder; class StringPrivate; - TAGLIB_SHARED_PTR d; + RefCountPtr d; }; /*! diff --git a/tests/test_smartptr.cpp b/tests/test_smartptr.cpp index cb481684..49165d07 100644 --- a/tests/test_smartptr.cpp +++ b/tests/test_smartptr.cpp @@ -26,7 +26,7 @@ public: void testSharedptrBasic() { int * ip = new int; - TAGLIB_SHARED_PTR cp ( ip ); + RefCountPtr cp ( ip ); CPPUNIT_ASSERT( ip == cp.get() ); CPPUNIT_ASSERT( cp.use_count() == 1 ); @@ -36,7 +36,7 @@ public: ck( static_cast(cp.get()), 54321 ); ck( static_cast(ip), *cp ); - TAGLIB_SHARED_PTR cp2 ( cp ); + RefCountPtr cp2 ( cp ); CPPUNIT_ASSERT( ip == cp2.get() ); CPPUNIT_ASSERT( cp.use_count() == 2 ); CPPUNIT_ASSERT( cp2.use_count() == 2 ); @@ -46,7 +46,7 @@ public: ck( static_cast(cp2.get()), 54321 ); ck( static_cast(ip), *cp2 ); - TAGLIB_SHARED_PTR cp3 ( cp ); + RefCountPtr cp3 ( cp ); CPPUNIT_ASSERT( cp.use_count() == 3 ); CPPUNIT_ASSERT( cp2.use_count() == 3 ); CPPUNIT_ASSERT( cp3.use_count() == 3 ); @@ -76,16 +76,16 @@ public: CPPUNIT_ASSERT( cp.use_count() == 3 ); CPPUNIT_ASSERT( *cp == 87654 ); - TAGLIB_SHARED_PTR cp4; + RefCountPtr cp4; swap( cp2, cp4 ); CPPUNIT_ASSERT( cp4.use_count() == 3 ); CPPUNIT_ASSERT( *cp4 == 87654 ); CPPUNIT_ASSERT( cp2.get() == 0 ); - std::set< TAGLIB_SHARED_PTR > scp; + std::set< RefCountPtr > scp; scp.insert(cp4); CPPUNIT_ASSERT( scp.find(cp4) != scp.end() ); - CPPUNIT_ASSERT( scp.find(cp4) == scp.find( TAGLIB_SHARED_PTR(cp4) ) ); + CPPUNIT_ASSERT( scp.find(cp4) == scp.find( RefCountPtr(cp4) ) ); } private: @@ -130,7 +130,7 @@ public: derivedDestructorCalled = false; { - TAGLIB_SHARED_PTR p1(new DummyDerived(100)); + RefCountPtr p1(new DummyDerived(100)); CPPUNIT_ASSERT(p1->getValue() == 100); } @@ -141,8 +141,8 @@ public: derivedDestructorCalled = false; { - TAGLIB_SHARED_PTR p1(new DummyDerived(100)); - TAGLIB_SHARED_PTR p2 = p1; + RefCountPtr p1(new DummyDerived(100)); + RefCountPtr p2 = p1; CPPUNIT_ASSERT(p1->getValue() == 100); CPPUNIT_ASSERT(p2->getValue() == 100); @@ -155,8 +155,8 @@ public: derivedDestructorCalled = false; { - TAGLIB_SHARED_PTR p1; - TAGLIB_SHARED_PTR p2; + RefCountPtr p1; + RefCountPtr p2; p1.reset(new DummyDerived(100)); p2 = p1; @@ -171,7 +171,7 @@ public: private: class DummyIncomplete; - TAGLIB_SHARED_PTR pincomplete; + RefCountPtr pincomplete; class DummyIncomplete { From 36d9fc1973e592b41af5e25848ae205861ac5f5a Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sat, 18 May 2013 23:30:15 +0900 Subject: [PATCH 03/10] Small change in Win9x support --- taglib/toolkit/tiostream.cpp | 43 +++++++++++++----------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/taglib/toolkit/tiostream.cpp b/taglib/toolkit/tiostream.cpp index 2d4f66d8..b7773975 100644 --- a/taglib/toolkit/tiostream.cpp +++ b/taglib/toolkit/tiostream.cpp @@ -29,30 +29,26 @@ using namespace TagLib; #ifdef _WIN32 -// MSVC 2008 or later can't produce the binary for Win9x. -#if !defined(_MSC_VER) || (_MSC_VER < 1500) +# include namespace { + // Check if the running system has CreateFileW() function. + // Windows9x systems don't have CreateFileW() or can't accept Unicode file names. - // Determines whether or not the running system is WinNT. - // In other words, whether the system supports Unicode. - - bool isWinNT() + bool supportsUnicode() { - OSVERSIONINFOA ver = {}; - ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - if(GetVersionExA(&ver)) { - return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT); - } - else { - return false; - } + const FARPROC p = GetProcAddress(GetModuleHandleA("kernel32"), "CreateFileW"); + return (p != NULL); } + + // Indicates whether the system supports Unicode file names. - const bool IsWinNT = isWinNT(); + const bool SystemSupportsUnicode = supportsUnicode(); // Converts a UTF-16 string into a local encoding. + // This function should only be used in Windows9x systems which don't support + // Unicode file names. std::string unicodeToAnsi(const std::wstring &wstr) { @@ -71,20 +67,11 @@ namespace // 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)) + : m_wname(SystemSupportsUnicode ? name : L"") + , m_name (SystemSupportsUnicode ? "" : unicodeToAnsi(name)) { } -#else - -FileName::FileName(const wchar_t *name) - : m_wname(name) -{ -} - -#endif - FileName::FileName(const char *name) : m_name(name) { @@ -92,7 +79,7 @@ FileName::FileName(const char *name) FileName::FileName(const FileName &name) : m_wname(name.m_wname) - , m_name(name.m_name) + , m_name (name.m_name) { } @@ -116,7 +103,7 @@ const std::string &FileName::str() const return m_name; } -#endif +#endif // _WIN32 //////////////////////////////////////////////////////////////////////////////// // public members From dcf11b95861a72f3c5c23ff0763ee2d74d948449 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 19 May 2013 02:33:17 +0900 Subject: [PATCH 04/10] Small refactoring of FileStream --- taglib/toolkit/tbytevector.cpp | 8 +- taglib/toolkit/tfilestream.cpp | 228 +++++++++++++++------------------ 2 files changed, 106 insertions(+), 130 deletions(-) diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 471af477..b3c8897f 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -729,9 +729,11 @@ TagLib::uint ByteVector::size() const ByteVector &ByteVector::resize(uint size, char padding) { - detach(); - d->data->data.resize(d->offset + size, padding); - d->length = size; + if(size != d->length) { + detach(); + d->data->data.resize(d->offset + size, padding); + d->length = size; + } return *this; } diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index 2ce5ab41..7a931cbe 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -51,9 +51,10 @@ namespace typedef FileName FileNameHandle; -# define INVALID_FILE INVALID_HANDLE_VALUE + typedef HANDLE FileHandle; + const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE; - HANDLE openFile(const FileName &path, bool readOnly) + inline FileHandle openFile(const FileName &path, bool readOnly) { const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); @@ -62,29 +63,32 @@ namespace else if(!path.str().empty()) return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); else - return INVALID_FILE; + return InvalidFileHandle; } - size_t fread(void *ptr, size_t size, size_t nmemb, HANDLE stream) + inline void closeFile(FileHandle file) { - DWORD readLen; - if(ReadFile(stream, ptr, size * nmemb, &readLen, NULL)) - return (readLen / size); + CloseHandle(file); + } + + inline size_t readFile(FileHandle file, ByteVector &buffer) + { + DWORD length; + if(ReadFile(file, buffer.data(), static_cast(buffer.size()), &length, NULL)) + return static_cast(length); else return 0; } - size_t fwrite(const void *ptr, size_t size, size_t nmemb, HANDLE stream) + inline size_t writeFile(FileHandle file, const ByteVector &buffer) { - DWORD writtenLen; - if(WriteFile(stream, ptr, size * nmemb, &writtenLen, NULL)) - return (writtenLen / size); + DWORD length; + if(WriteFile(file, buffer.data(), static_cast(buffer.size()), &length, NULL)) + return static_cast(length); else 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. @@ -111,78 +115,59 @@ namespace } } -# endif - #else -# define INVALID_FILE 0 - struct FileNameHandle : public std::string { FileNameHandle(FileName name) : std::string(name) {} operator FileName () const { return c_str(); } }; - FILE *openFile(const FileName &path, bool readOnly) + typedef FILE* FileHandle; + const FileHandle InvalidFileHandle = 0; + + inline FileHandle openFile(const FileName &path, bool readOnly) { return fopen(path, readOnly ? "rb" : "rb+"); } + inline void closeFile(FileHandle file) + { + fclose(file); + } + + inline size_t readFile(FileHandle file, ByteVector &buffer) + { + return fread(buffer.data(), sizeof(char), buffer.size(), file); + } + + inline size_t writeFile(FileHandle file, const ByteVector &buffer) + { + return fwrite(buffer.data(), sizeof(char), buffer.size(), file); + } + #endif } class FileStream::FileStreamPrivate { public: - FileStreamPrivate(const FileName &fileName, bool openReadOnly); - -#ifdef _WIN32 - - HANDLE file; - -#else - - FILE *file; - -#endif + FileStreamPrivate(const FileName &fileName, bool openReadOnly) + : file(InvalidFileHandle) + , name(fileName) + , readOnly(openReadOnly) + , size(0) + { + } + FileHandle file; FileNameHandle name; - bool readOnly; ulong size; + static const uint bufferSize = 1024; }; -FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool openReadOnly) : - file(INVALID_FILE), - name(fileName), - readOnly(true), - size(0) -{ - // First try with read / write mode, if that fails, fall back to read only. - - if(!openReadOnly) - file = openFile(name, false); - - if(file != INVALID_FILE) - readOnly = false; - else - file = openFile(name, true); - - if(file == INVALID_FILE) - { -# ifdef _WIN32 - - debug("Could not open file " + fileNameToString(name)); - -# else - - debug("Could not open file " + String((const char *) name)); - -# endif - } -} - //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -190,21 +175,30 @@ FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool FileStream::FileStream(FileName file, bool openReadOnly) : d(new FileStreamPrivate(file, openReadOnly)) { + // First try with read / write mode, if that fails, fall back to read only. + + if(!openReadOnly) + d->file = openFile(file, false); + + if(d->file != InvalidFileHandle) + d->readOnly = false; + else + d->file = openFile(d->name, true); + + if(d->file == InvalidFileHandle) + { +# ifdef _WIN32 + debug("Could not open file " + fileNameToString(d->name)); +# else + debug("Could not open file " + String(static_cast(d->name))); +# endif + } } FileStream::~FileStream() { -#ifdef _WIN32 - if(isOpen()) - CloseHandle(d->file); - -#else - - if(isOpen()) - fclose(d->file); - -#endif + closeFile(d->file); delete d; } @@ -224,16 +218,16 @@ ByteVector FileStream::readBlock(ulong length) if(length == 0) return ByteVector::null; - if(length > FileStreamPrivate::bufferSize && - length > ulong(FileStream::length())) - { - length = FileStream::length(); - } + const ulong streamLength = static_cast(FileStream::length()); + if(length > bufferSize() && length > streamLength) + length = streamLength; - ByteVector v(static_cast(length)); - const int count = fread(v.data(), sizeof(char), length, d->file); - v.resize(count); - return v; + ByteVector buffer(static_cast(length)); + + const size_t count = readFile(d->file, buffer); + buffer.resize(static_cast(count)); + + return buffer; } void FileStream::writeBlock(const ByteVector &data) @@ -248,7 +242,7 @@ void FileStream::writeBlock(const ByteVector &data) return; } - fwrite(data.data(), sizeof(char), data.size(), d->file); + writeFile(d->file, data); } void FileStream::insert(const ByteVector &data, ulong start, ulong replace) @@ -269,10 +263,10 @@ void FileStream::insert(const ByteVector &data, ulong start, ulong replace) return; } else if(data.size() < replace) { - seek(start); - writeBlock(data); - removeBlock(start + data.size(), replace - data.size()); - return; + seek(start); + writeBlock(data); + removeBlock(start + data.size(), replace - data.size()); + return; } // Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore @@ -295,64 +289,41 @@ void FileStream::insert(const ByteVector &data, ulong start, ulong replace) long readPosition = start + replace; long writePosition = start; - ByteVector buffer; + ByteVector buffer = data; ByteVector aboutToOverwrite(static_cast(bufferLength)); - // This is basically a special case of the loop below. Here we're just - // doing the same steps as below, but since we aren't using the same buffer - // size -- instead we're using the tag size -- this has to be handled as a - // special case. We're also using File::writeBlock() just for the tag. - // That's a bit slower than using char *'s so, we're only doing it here. - - seek(readPosition); - int bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file); - readPosition += bufferLength; - - seek(writePosition); - writeBlock(data); - writePosition += data.size(); - - buffer = aboutToOverwrite; - - // In case we've already reached the end of file... - - buffer.resize(bytesRead); - - // Ok, here's the main loop. We want to loop until the read fails, which - // means that we hit the end of the file. - - while(!buffer.isEmpty()) { - + while(true) + { // Seek to the current read position and read the data that we're about // to overwrite. Appropriately increment the readPosition. - + seek(readPosition); - bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file); + const size_t bytesRead = readFile(d->file, aboutToOverwrite); aboutToOverwrite.resize(bytesRead); readPosition += bufferLength; // Check to see if we just read the last block. We need to call clear() // if we did so that the last write succeeds. - if(ulong(bytesRead) < bufferLength) + if(bytesRead < bufferLength) clear(); // Seek to the write position and write our buffer. Increment the // writePosition. seek(writePosition); - fwrite(buffer.data(), sizeof(char), buffer.size(), d->file); + writeBlock(buffer); + + // We hit the end of the file. + + if(bytesRead == 0) + break; + writePosition += buffer.size(); // Make the current buffer the data that we read in the beginning. - + buffer = aboutToOverwrite; - - // Again, we need this for the last write. We don't want to write garbage - // at the end of our file, so we need to set the buffer size to the amount - // that we actually read. - - bufferLength = bytesRead; } } @@ -370,11 +341,9 @@ void FileStream::removeBlock(ulong start, ulong length) ByteVector buffer(static_cast(bufferLength)); - ulong bytesRead = 1; - - while(bytesRead != 0) { + while(true) { seek(readPosition); - bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file); + const size_t bytesRead = readFile(d->file, buffer); readPosition += bytesRead; // Check to see if we just read the last block. We need to call clear() @@ -384,9 +353,14 @@ void FileStream::removeBlock(ulong start, ulong length) clear(); seek(writePosition); - fwrite(buffer.data(), sizeof(char), bytesRead, d->file); + writeFile(d->file, buffer); + + if(bytesRead == 0) + break; + writePosition += bytesRead; } + truncate(writePosition); } @@ -397,7 +371,7 @@ bool FileStream::readOnly() const bool FileStream::isOpen() const { - return (d->file != INVALID_FILE); + return (d->file != InvalidFileHandle); } void FileStream::seek(long offset, Position p) From 5c3f096fe4a77219f73e94e9b9f66677ad515ddb Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 19 May 2013 11:09:43 +0900 Subject: [PATCH 05/10] Fixed initialization of FileStream --- taglib/toolkit/tfile.cpp | 9 +-------- taglib/toolkit/tfile.h | 2 +- taglib/toolkit/tfilestream.cpp | 36 +++++++++++++++------------------- taglib/toolkit/tiostream.cpp | 12 +++++++++--- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/taglib/toolkit/tfile.cpp b/taglib/toolkit/tfile.cpp index fdb5237f..a229e85f 100644 --- a/taglib/toolkit/tfile.cpp +++ b/taglib/toolkit/tfile.cpp @@ -29,21 +29,14 @@ #include "tdebug.h" #include "tpropertymap.h" -#include -#include -#include - #ifdef _WIN32 -# include # include # include -# define ftruncate _chsize #else +# include # include #endif -#include - #ifndef R_OK # define R_OK 4 #endif diff --git a/taglib/toolkit/tfile.h b/taglib/toolkit/tfile.h index 30e53f93..67f6f80f 100644 --- a/taglib/toolkit/tfile.h +++ b/taglib/toolkit/tfile.h @@ -213,7 +213,7 @@ namespace TagLib { bool isOpen() const; /*! - * Returns true if the file is open and readble. + * Returns true if the file is open and readable. */ bool isValid() const; diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index 7a931cbe..1798134f 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -27,20 +27,13 @@ #include "tstring.h" #include "tdebug.h" -#include -#include -#include - #ifdef _WIN32 -# include # include -# include #else +# include # include #endif -#include - using namespace TagLib; namespace @@ -89,11 +82,12 @@ namespace return 0; } +# ifndef NDEBUG + // 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. + // Debugging use only. In actual use, file names in local encodings are passed to + // CreateFileA() without any conversions. String fileNameToString(const FileName &name) { @@ -115,7 +109,9 @@ namespace } } -#else +# endif + +#else // _WIN32 struct FileNameHandle : public std::string { @@ -146,16 +142,16 @@ namespace return fwrite(buffer.data(), sizeof(char), buffer.size(), file); } -#endif +#endif // _WIN32 } class FileStream::FileStreamPrivate { public: - FileStreamPrivate(const FileName &fileName, bool openReadOnly) + FileStreamPrivate(const FileName &fileName) : file(InvalidFileHandle) , name(fileName) - , readOnly(openReadOnly) + , readOnly(true) , size(0) { } @@ -172,23 +168,23 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -FileStream::FileStream(FileName file, bool openReadOnly) - : d(new FileStreamPrivate(file, openReadOnly)) +FileStream::FileStream(FileName fileName, bool openReadOnly) + : d(new FileStreamPrivate(fileName)) { // First try with read / write mode, if that fails, fall back to read only. if(!openReadOnly) - d->file = openFile(file, false); + d->file = openFile(fileName, false); if(d->file != InvalidFileHandle) d->readOnly = false; else - d->file = openFile(d->name, true); + d->file = openFile(fileName, true); if(d->file == InvalidFileHandle) { # ifdef _WIN32 - debug("Could not open file " + fileNameToString(d->name)); + debug("Could not open file " + fileNameToString(fileName)); # else debug("Could not open file " + String(static_cast(d->name))); # endif diff --git a/taglib/toolkit/tiostream.cpp b/taglib/toolkit/tiostream.cpp index b7773975..2832e414 100644 --- a/taglib/toolkit/tiostream.cpp +++ b/taglib/toolkit/tiostream.cpp @@ -29,6 +29,8 @@ using namespace TagLib; #ifdef _WIN32 +# include "tstring.h" +# include "tdebug.h" # include namespace @@ -50,14 +52,18 @@ namespace // This function should only be used in Windows9x systems which don't support // Unicode file names. - std::string unicodeToAnsi(const std::wstring &wstr) + std::string unicodeToAnsi(const wchar_t *wstr) { - const int len = WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, NULL, 0, NULL, NULL); + if(SystemSupportsUnicode) { + debug("unicodeToAnsi() - Should not be used on WinNT systems."); + } + + const int len = WideCharToMultiByte(CP_ACP, 0, wstr, -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); + WideCharToMultiByte(CP_ACP, 0, wstr, -1, &str[0], len, NULL, NULL); return str; } From 79f3edebc06529baa1b044fd264556665565a168 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 19 May 2013 11:59:37 +0900 Subject: [PATCH 06/10] Added myself to AUTHORS --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 3683f3fb..e996d941 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,8 @@ Teemu Tervo Numerous bug reports and fixes Mathias Panzenböck Mod, S3M, IT and XM metadata implementations +Tsuda Kageyu + A lot of fixes and improvements, i.e. memory copy reduction etc. Please send all patches and questions to taglib-devel@kde.org rather than to individual developers! From bbec1c7f81b8f59567fc8868aca61deb38acafeb Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 19 May 2013 14:39:45 +0900 Subject: [PATCH 07/10] Changed String::number() to use a standard function --- ConfigureChecks.cmake | 14 ++++++++++++++ config.h.cmake | 4 ++++ taglib/toolkit/tstring.cpp | 36 ++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 440a4414..46611a00 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -183,6 +183,20 @@ if(NOT HAVE_GCC_BYTESWAP_16 OR NOT HAVE_GCC_BYTESWAP_32 OR NOT HAVE_GCC_BYTESWAP endif() endif() +# Determine whether your compiler supports some safer version of sprintf. + +check_cxx_source_compiles(" + #include + int main() { char buf[20]; snprintf(buf, 20, \"%d\", 1); return 0; } +" HAVE_SNPRINTF) + +if(NOT HAVE_SNPRINTF) + check_cxx_source_compiles(" + #include + int main() { char buf[20]; sprintf_s(buf, \"%d\", 1); return 0; } + " HAVE_SPRINTF_S) +endif() + # Determine whether your compiler supports codecvt. check_cxx_source_compiles(" diff --git a/config.h.cmake b/config.h.cmake index 436ca440..15d2f997 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -24,6 +24,10 @@ #cmakedefine HAVE_WIN_ATOMIC 1 #cmakedefine HAVE_IA64_ATOMIC 1 +/* Defined if your compiler supports some safer version of sprintf */ +#cmakedefine HAVE_SNPRINTF 1 +#cmakedefine HAVE_SPRINTF_S 1 + /* Defined if you have libz */ #cmakedefine HAVE_ZLIB 1 diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index cf745f81..7b4d2040 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -33,7 +33,8 @@ #include "trefcounter.h" #include -#include +#include +#include #if defined(HAVE_MSC_BYTESWAP) # include @@ -597,31 +598,30 @@ bool String::isAscii() const String String::number(int n) // static { - if(n == 0) - return String("0"); + static const size_t BufferSize = 11; // Sufficient to store "-214748364". + static const char *Format = "%d"; - String charStack; + char buffer[BufferSize]; + int length; - bool negative = n < 0; +#if defined(HAVE_SNPRINTF) - if(negative) - n = n * -1; + length = snprintf(buffer, BufferSize, Format, n); - while(n > 0) { - int remainder = n % 10; - charStack += char(remainder + '0'); - n = (n - remainder) / 10; - } +#elif defined(HAVE_SPRINTF_S) - String s; + length = sprintf_s(buffer, Format, n); - if(negative) - s += '-'; +#else - for(int i = charStack.d->data.size() - 1; i >= 0; i--) - s += charStack.d->data[i]; + length = sprintf(buffer, Format, n); - return s; +#endif + + if(length > 0) + return String(buffer); + else + return String::null; } TagLib::wchar &String::operator[](int i) From 437b61a3118519902633285442105bbfd097235f Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 19 May 2013 21:56:05 +0900 Subject: [PATCH 08/10] Rewrote File, FileRef and FileStream to use smart pointers --- bindings/c/tag_c.cpp | 36 ++--- taglib/fileref.cpp | 247 ++++++++++++++++++++------------- taglib/fileref.h | 64 ++++++--- taglib/toolkit/tfile.cpp | 222 ++++++++++++----------------- taglib/toolkit/tfile.h | 26 +--- taglib/toolkit/tfilestream.cpp | 22 +-- taglib/toolkit/tfilestream.h | 7 +- tests/test_fileref.cpp | 24 ++++ 8 files changed, 349 insertions(+), 299 deletions(-) diff --git a/bindings/c/tag_c.cpp b/bindings/c/tag_c.cpp index 5b739d6f..e5436cea 100644 --- a/bindings/c/tag_c.cpp +++ b/bindings/c/tag_c.cpp @@ -47,12 +47,12 @@ static bool stringManagementEnabled = true; void taglib_set_strings_unicode(BOOL unicode) { - unicodeStrings = bool(unicode); + unicodeStrings = (unicode != 0); } void taglib_set_string_management_enabled(BOOL management) { - stringManagementEnabled = bool(management); + stringManagementEnabled = (management != 0); } void taglib_free(void* pointer) @@ -66,32 +66,32 @@ void taglib_free(void* pointer) TagLib_File *taglib_file_new(const char *filename) { - return reinterpret_cast(FileRef::create(filename)); + return reinterpret_cast(new FileRef(filename)); } TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type) { switch(type) { case TagLib_File_MPEG: - return reinterpret_cast(new MPEG::File(filename)); + return reinterpret_cast(new FileRef(new MPEG::File(filename))); case TagLib_File_OggVorbis: - return reinterpret_cast(new Ogg::Vorbis::File(filename)); + return reinterpret_cast(new FileRef(new Ogg::Vorbis::File(filename))); case TagLib_File_FLAC: - return reinterpret_cast(new FLAC::File(filename)); + return reinterpret_cast(new FileRef(new FLAC::File(filename))); case TagLib_File_MPC: - return reinterpret_cast(new MPC::File(filename)); + return reinterpret_cast(new FileRef(new MPC::File(filename))); case TagLib_File_OggFlac: - return reinterpret_cast(new Ogg::FLAC::File(filename)); + return reinterpret_cast(new FileRef(new Ogg::FLAC::File(filename))); case TagLib_File_WavPack: - return reinterpret_cast(new WavPack::File(filename)); + return reinterpret_cast(new FileRef(new WavPack::File(filename))); case TagLib_File_Speex: - return reinterpret_cast(new Ogg::Speex::File(filename)); + return reinterpret_cast(new FileRef(new Ogg::Speex::File(filename))); case TagLib_File_TrueAudio: - return reinterpret_cast(new TrueAudio::File(filename)); + return reinterpret_cast(new FileRef(new TrueAudio::File(filename))); case TagLib_File_MP4: - return reinterpret_cast(new MP4::File(filename)); + return reinterpret_cast(new FileRef(new MP4::File(filename))); case TagLib_File_ASF: - return reinterpret_cast(new ASF::File(filename)); + return reinterpret_cast(new FileRef(new ASF::File(filename))); default: return 0; } @@ -101,29 +101,29 @@ TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type) void taglib_file_free(TagLib_File *file) { - delete reinterpret_cast(file); + delete reinterpret_cast(file); } BOOL taglib_file_is_valid(const TagLib_File *file) { - return reinterpret_cast(file)->isValid(); + return reinterpret_cast(file)->isValid(); } TagLib_Tag *taglib_file_tag(const TagLib_File *file) { - const File *f = reinterpret_cast(file); + const FileRef *f = reinterpret_cast(file); return reinterpret_cast(f->tag()); } const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file) { - const File *f = reinterpret_cast(file); + const FileRef *f = reinterpret_cast(file); return reinterpret_cast(f->audioProperties()); } BOOL taglib_file_save(TagLib_File *file) { - return reinterpret_cast(file)->save(); + return reinterpret_cast(file)->save(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index f24f4c56..77c78069 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -59,24 +59,130 @@ using namespace TagLib; +namespace +{ + typedef List ResolverList; + typedef ResolverList::ConstIterator ResolverConstIterator; + + ResolverList fileTypeResolvers; + + RefCountPtr create( + FileName fileName, + bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { + RefCountPtr file; + for(ResolverConstIterator it = fileTypeResolvers.begin(); it != fileTypeResolvers.end(); ++it) + { + file.reset((*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle)); + if(file) + return file; + } + + String ext; + +#ifdef _WIN32 + // 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 + { + String s = fileName; + const size_t pos = s.rfind("."); + if(pos != String::npos) + 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. + + if(!ext.isEmpty()) { + if(ext == "MP3") + file.reset(new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "OGG") + file.reset(new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "OGA") { + /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ + file.reset(new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle)); + if(!file->isValid()) + file.reset(new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle)); + } + else if(ext == "FLAC") + file.reset(new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "MPC") + file.reset(new MPC::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "WV") + file.reset(new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "SPX") + file.reset(new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "OPUS") + file.reset(new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "TTA") + file.reset(new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") + file.reset(new MP4::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "WMA" || ext == "ASF") + file.reset(new ASF::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "AIF" || ext == "AIFF") + file.reset(new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "WAV") + file.reset(new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "APE") + file.reset(new APE::File(fileName, readAudioProperties, audioPropertiesStyle)); + // module, nst and wow are possible but uncommon extensions + else if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") + file.reset(new Mod::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "S3M") + file.reset(new S3M::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "IT") + file.reset(new IT::File(fileName, readAudioProperties, audioPropertiesStyle)); + else if(ext == "XM") + file.reset(new XM::File(fileName, readAudioProperties, audioPropertiesStyle)); + } + + return file; + } +} + class FileRef::FileRefPrivate { public: - FileRefPrivate(File *f) : file(f) {} + FileRefPrivate() + : file() + { + } + + FileRefPrivate(File *f) + : file(f) + { + } + + FileRefPrivate(RefCountPtr f) + : file(f) + { + } RefCountPtr file; - - static List fileTypeResolvers; }; -List FileRef::FileRefPrivate::fileTypeResolvers; - //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// FileRef::FileRef() - : d(new FileRefPrivate(0)) + : d(new FileRefPrivate()) { } @@ -118,6 +224,36 @@ Tag *FileRef::tag() const return d->file->tag(); } +PropertyMap FileRef::properties() const +{ + if(isNull()) { + debug("FileRef::properties() - Called without a valid file."); + return PropertyMap(); + } + + return d->file->properties(); +} + +void FileRef::removeUnsupportedProperties(const StringList& properties) +{ + if(isNull()) { + debug("FileRef::removeUnsupportedProperties() - Called without a valid file."); + return; + } + + d->file->removeUnsupportedProperties(properties); +} + +PropertyMap FileRef::setProperties(const PropertyMap &properties) +{ + if(isNull()) { + debug("FileRef::setProperties() - Called without a valid file."); + return PropertyMap(); + } + + return d->file->setProperties(properties); +} + AudioProperties *FileRef::audioProperties() const { if(isNull()) { @@ -143,7 +279,7 @@ bool FileRef::save() const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static { - FileRefPrivate::fileTypeResolvers.prepend(resolver); + fileTypeResolvers.prepend(resolver); return resolver; } @@ -182,9 +318,14 @@ StringList FileRef::defaultFileExtensions() return l; } +bool FileRef::isValid() const +{ + return (d->file && d->file->isValid()); +} + bool FileRef::isNull() const { - return !d->file || !d->file->isValid(); + return !isValid(); } FileRef &FileRef::operator=(const FileRef &ref) @@ -212,93 +353,3 @@ bool FileRef::operator!=(const FileRef &ref) const { return ref.d->file != d->file; } - -File *FileRef::create(FileName fileName, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) // static -{ - - List::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin(); - - for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) { - File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); - if(file) - return file; - } - - String ext; - -#ifdef _WIN32 - // 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 - { - String s = fileName; - const size_t pos = s.rfind("."); - if(pos != String::npos) - 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. - - if(!ext.isEmpty()) { - if(ext == "MP3") - return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OGG") - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OGA") { - /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ - File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if (file->isValid()) - return file; - delete file; - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - } - if(ext == "FLAC") - return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "MPC") - return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WV") - return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "SPX") - return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OPUS") - return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "TTA") - return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") - return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WMA" || ext == "ASF") - return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "AIF" || ext == "AIFF") - return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WAV") - return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "APE") - return new APE::File(fileName, readAudioProperties, audioPropertiesStyle); - // module, nst and wow are possible but uncommon extensions - if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") - return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "S3M") - return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "IT") - return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "XM") - return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); - } - - return 0; -} diff --git a/taglib/fileref.h b/taglib/fileref.h index c323b086..465730f0 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -26,10 +26,10 @@ #ifndef TAGLIB_FILEREF_H #define TAGLIB_FILEREF_H +#include "taglib_export.h" #include "tfile.h" #include "tstringlist.h" - -#include "taglib_export.h" +#include "tpropertymap.h" #include "audioproperties.h" #if _WIN32 @@ -172,6 +172,41 @@ namespace TagLib { */ Tag *tag() const; + /*! + * Exports the tags of the file as dictionary mapping (human readable) tag + * names (uppercase Strings) to StringLists of tag values. Calls the according + * specialization in the File subclasses. + * For each metadata object of the file that could not be parsed into the PropertyMap + * format, the returend map's unsupportedData() list will contain one entry identifying + * that object (e.g. the frame type for ID3v2 tags). Use removeUnsupportedProperties() + * to remove (a subset of) them. + * For files that contain more than one tag (e.g. an MP3 with both an ID3v1 and an ID3v2 + * tag) only the most "modern" one will be exported (ID3v2 in this case). + */ + PropertyMap properties() const; + + /*! + * Removes unsupported properties, or a subset of them, from the file's metadata. + * The parameter \a properties must contain only entries from + * properties().unsupportedData(). + */ + void removeUnsupportedProperties(const StringList& properties); + + /*! + * Sets the tags of this File to those specified in \a properties. Calls the + * according specialization method in the subclasses of File to do the translation + * into the format-specific details. + * If some value(s) could not be written imported to the specific metadata format, + * the returned PropertyMap will contain those value(s). Otherwise it will be empty, + * indicating that no problems occured. + * With file types that support several tag formats (for instance, MP3 files can have + * ID3v1, ID3v2, and APEv2 tags), this function will create the most appropriate one + * (ID3v2 for MP3 files). Older formats will be updated as well, if they exist, but won't + * be taken into account for the return value of this function. + * See the documentation of the subclass implementations for detailed descriptions. + */ + PropertyMap setProperties(const PropertyMap &properties); + /*! * Returns the audio properties for this FileRef. If no audio properties * were read then this will returns a null pointer. @@ -232,8 +267,17 @@ namespace TagLib { */ static StringList defaultFileExtensions(); + /*! + * Returns true if the file is open and readable. + * + * \note Just a negative of isNull(). + */ + bool isValid() const; + /*! * Returns true if the file (and as such other pointers) are null. + * + * \note Just a negative of isValid(). */ bool isNull() const; @@ -264,22 +308,6 @@ namespace TagLib { */ bool operator!=(const FileRef &ref) const; - /*! - * A simple implementation of file type guessing. If \a readAudioProperties - * is true then the audio properties will be read using - * \a audioPropertiesStyle. If \a readAudioProperties is false then - * \a audioPropertiesStyle will be ignored. - * - * \note You generally shouldn't use this method, but instead the constructor - * directly. - * - * \deprecated - */ - static File *create(FileName fileName, - bool readAudioProperties = true, - AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); - - private: class FileRefPrivate; RefCountPtr d; diff --git a/taglib/toolkit/tfile.cpp b/taglib/toolkit/tfile.cpp index bcd621df..4e3c4f1a 100644 --- a/taglib/toolkit/tfile.cpp +++ b/taglib/toolkit/tfile.cpp @@ -28,96 +28,76 @@ #include "tstring.h" #include "tdebug.h" #include "tpropertymap.h" - -#ifdef _WIN32 -# include -# include -#else -# include -# include -#endif - -#ifndef R_OK -# define R_OK 4 -#endif -#ifndef W_OK -# define W_OK 2 -#endif - -#include "asffile.h" -#include "mpegfile.h" -#include "vorbisfile.h" -#include "flacfile.h" -#include "oggflacfile.h" -#include "mpcfile.h" -#include "mp4file.h" -#include "wavpackfile.h" -#include "speexfile.h" -#include "opusfile.h" -#include "trueaudiofile.h" -#include "aifffile.h" -#include "wavfile.h" -#include "apefile.h" -#include "modfile.h" -#include "s3mfile.h" -#include "itfile.h" -#include "xmfile.h" -#include "mp4file.h" +#include "audioproperties.h" using namespace TagLib; -class File::FilePrivate +class File::FilePrivateBase { public: - FilePrivate(IOStream *stream, bool owner); + FilePrivateBase() + : valid(true) + { + } + + virtual ~FilePrivateBase() + { + } + + virtual IOStream *stream() const = 0; - IOStream *stream; - bool streamOwner; bool valid; - -#ifdef _WIN32 - - static const size_t bufferSize = 8192; - -#else - - static const size_t bufferSize = 1024; - -#endif }; -File::FilePrivate::FilePrivate(IOStream *stream, bool owner) : - stream(stream), - streamOwner(owner), - valid(true) +// FilePrivate implementation which takes ownership of the stream. + +class File::ManagedFilePrivate : public File::FilePrivateBase { -} +public: + ManagedFilePrivate(IOStream *stream) + : p(stream) + { + } + + virtual IOStream *stream() const + { + return p.get(); + } + +private: + NonRefCountPtr p; +}; + +// FilePrivate implementation which doesn't take ownership of the stream. + +class File::UnmanagedFilePrivate : public File::FilePrivateBase +{ +public: + UnmanagedFilePrivate(IOStream *stream) + : p(stream) + { + } + + virtual IOStream *stream() const + { + return p; + } + +private: + IOStream *p; +}; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// -File::File(FileName fileName) -{ - IOStream *stream = new FileStream(fileName); - d = new FilePrivate(stream, true); -} - -File::File(IOStream *stream) -{ - d = new FilePrivate(stream, false); -} - File::~File() { - if(d->stream && d->streamOwner) - delete d->stream; - delete d; } FileName File::name() const { - return d->stream->name(); + return d->stream()->name(); } PropertyMap File::properties() const @@ -137,17 +117,17 @@ PropertyMap File::setProperties(const PropertyMap &properties) ByteVector File::readBlock(size_t length) { - return d->stream->readBlock(length); + return d->stream()->readBlock(length); } void File::writeBlock(const ByteVector &data) { - d->stream->writeBlock(data); + d->stream()->writeBlock(data); } offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVector &before) { - if(!d->stream || pattern.size() > d->bufferSize) + if(!d->stream() || pattern.size() > bufferSize()) return -1; // The position in the file that the current buffer starts at. @@ -196,20 +176,20 @@ offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVe // (1) previous partial match if(previousPartialMatch != ByteVector::npos - && d->bufferSize > previousPartialMatch) + && bufferSize() > previousPartialMatch) { - const size_t patternOffset = (d->bufferSize - previousPartialMatch); + const size_t patternOffset = (bufferSize() - previousPartialMatch); if(buffer.containsAt(pattern, 0, patternOffset)) { seek(originalPosition); - return bufferOffset - d->bufferSize + previousPartialMatch; + return bufferOffset - bufferSize() + previousPartialMatch; } } if(!before.isNull() && beforePreviousPartialMatch != ByteVector::npos - && d->bufferSize > beforePreviousPartialMatch) + && bufferSize() > beforePreviousPartialMatch) { - const size_t beforeOffset = (d->bufferSize - beforePreviousPartialMatch); + const size_t beforeOffset = (bufferSize() - beforePreviousPartialMatch); if(buffer.containsAt(before, 0, beforeOffset)) { seek(originalPosition); return -1; @@ -236,7 +216,7 @@ offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVe if(!before.isNull()) beforePreviousPartialMatch = buffer.endsWithPartialMatch(before); - bufferOffset += d->bufferSize; + bufferOffset += bufferSize(); } // Since we hit the end of the file, reset the status before continuing. @@ -251,21 +231,9 @@ offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVe offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteVector &before) { - if(!d->stream || pattern.size() > d->bufferSize) + if(!d->stream() || pattern.size() > bufferSize()) return -1; - // The position in the file that the current buffer starts at. - - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - /* - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; - */ - // Save the location of the current read pointer. We will restore the // position using seek() before all returns. @@ -275,17 +243,21 @@ offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteV offset_t bufferOffset; if(fromOffset == 0) { - seek(-1 * int(d->bufferSize), End); + seek(-1 * int(bufferSize()), End); bufferOffset = tell(); } else { - seek(fromOffset + -1 * int(d->bufferSize), Beginning); + seek(fromOffset + -1 * int(bufferSize()), Beginning); bufferOffset = tell(); } // See the notes in find() for an explanation of this algorithm. - for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) { + while(true) + { + ByteVector buffer = readBlock(bufferSize()); + if(buffer.isEmpty()) + break; // TODO: (1) previous partial match @@ -304,7 +276,7 @@ offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteV // TODO: (3) partial match - bufferOffset -= d->bufferSize; + bufferOffset -= bufferSize(); seek(bufferOffset); } @@ -319,22 +291,22 @@ offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteV void File::insert(const ByteVector &data, offset_t start, size_t replace) { - d->stream->insert(data, start, replace); + d->stream()->insert(data, start, replace); } void File::removeBlock(offset_t start, size_t length) { - d->stream->removeBlock(start, length); + d->stream()->removeBlock(start, length); } bool File::readOnly() const { - return d->stream->readOnly(); + return d->stream()->readOnly(); } bool File::isOpen() const { - return d->stream->isOpen(); + return d->stream()->isOpen(); } bool File::isValid() const @@ -344,57 +316,27 @@ bool File::isValid() const void File::seek(offset_t offset, Position p) { - d->stream->seek(offset, IOStream::Position(p)); + d->stream()->seek(offset, IOStream::Position(p)); } void File::truncate(offset_t length) { - d->stream->truncate(length); + d->stream()->truncate(length); } void File::clear() { - d->stream->clear(); + d->stream()->clear(); } offset_t File::tell() const { - return d->stream->tell(); + return d->stream()->tell(); } offset_t File::length() { - return d->stream->length(); -} - -bool File::isReadable(const char *file) -{ - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later - - return _access_s(file, R_OK) == 0; - -#else - - return access(file, R_OK) == 0; - -#endif - -} - -bool File::isWritable(const char *file) -{ - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later - - return _access_s(file, W_OK) == 0; - -#else - - return access(file, W_OK) == 0; - -#endif - + return d->stream()->length(); } String File::toString() const @@ -415,9 +357,19 @@ String File::toString() const // protected members //////////////////////////////////////////////////////////////////////////////// +File::File(const FileName &fileName) + : d(new ManagedFilePrivate(new FileStream(fileName))) +{ +} + +File::File(IOStream *stream) + : d(new UnmanagedFilePrivate(stream)) +{ +} + size_t File::bufferSize() { - return FilePrivate::bufferSize; + return FileStream::bufferSize(); } void File::setValid(bool valid) diff --git a/taglib/toolkit/tfile.h b/taglib/toolkit/tfile.h index 14d2fe89..680958e0 100644 --- a/taglib/toolkit/tfile.h +++ b/taglib/toolkit/tfile.h @@ -235,21 +235,6 @@ namespace TagLib { */ offset_t length(); - /*! - * Returns true if \a file can be opened for reading. If the file does not - * exist, this will return false. - * - * \deprecated - */ - static bool isReadable(const char *file); - - /*! - * Returns true if \a file can be opened for writing. - * - * \deprecated - */ - static bool isWritable(const char *name); - /*! * Returns description of the audio file and its tags. */ @@ -257,13 +242,12 @@ namespace TagLib { protected: /*! - * Construct a File object and opens the \a file. \a file should be a - * be a C-string in the local file system encoding. + * Construct a File object and opens the file specified by \a fileName. * * \note Constructor is protected since this class should only be * instantiated through subclasses. */ - File(FileName file); + File(const FileName &fileName); /*! * Construct a File object and use the \a stream instance. @@ -297,8 +281,10 @@ namespace TagLib { File(const File &); File &operator=(const File &); - class FilePrivate; - FilePrivate *d; + class FilePrivateBase; + class ManagedFilePrivate; + class UnmanagedFilePrivate; + NonRefCountPtr d; }; } diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index 2af442e5..f3877f68 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -43,8 +43,9 @@ namespace // Using Win32 native API instead of standard C file I/O to reduce the resource consumption. typedef FileName FileNameHandle; - typedef HANDLE FileHandle; + + const size_t BufferSize = 8192; const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE; inline FileHandle openFile(const FileName &path, bool readOnly) @@ -120,6 +121,8 @@ namespace }; typedef FILE* FileHandle; + + const size_t BufferSize = 1024; const FileHandle InvalidFileHandle = 0; inline FileHandle openFile(const FileName &path, bool readOnly) @@ -160,8 +163,6 @@ public: FileNameHandle name; bool readOnly; offset_t size; - - static const uint bufferSize = 1024; }; //////////////////////////////////////////////////////////////////////////////// @@ -195,8 +196,6 @@ FileStream::~FileStream() { if(isOpen()) closeFile(d->file); - - delete d; } FileName FileStream::name() const @@ -215,7 +214,7 @@ ByteVector FileStream::readBlock(size_t length) return ByteVector::null; const offset_t streamLength = FileStream::length(); - if(length > FileStreamPrivate::bufferSize && static_cast(length) > streamLength) + if(length > BufferSize && static_cast(length) > streamLength) length = static_cast(streamLength); ByteVector buffer(length); @@ -275,10 +274,10 @@ void FileStream::insert(const ByteVector &data, offset_t start, size_t replace) // the *differnce* in the tag sizes. We want to avoid overwriting parts // that aren't yet in memory, so this is necessary. - size_t bufferLength = FileStreamPrivate::bufferSize; + size_t bufferLength = BufferSize; while(data.size() - replace > bufferLength) - bufferLength += FileStreamPrivate::bufferSize; + bufferLength += BufferSize; // Set where to start the reading and writing. @@ -333,7 +332,7 @@ void FileStream::removeBlock(offset_t start, size_t length) return; } - size_t bufferLength = FileStreamPrivate::bufferSize; + size_t bufferLength = BufferSize; offset_t readPosition = start + length; offset_t writePosition = start; @@ -525,6 +524,11 @@ offset_t FileStream::length() #endif } +size_t FileStream::bufferSize() +{ + return BufferSize; +} + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tfilestream.h b/taglib/toolkit/tfilestream.h index 413245c3..80240ad5 100644 --- a/taglib/toolkit/tfilestream.h +++ b/taglib/toolkit/tfilestream.h @@ -135,9 +135,14 @@ namespace TagLib { */ void truncate(offset_t length); + /*! + * Returns the buffer size that is used for internal buffering. + */ + static size_t bufferSize(); + private: class FileStreamPrivate; - FileStreamPrivate *d; + NonRefCountPtr d; }; } diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index 06663c97..8cf1e8df 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -37,6 +37,7 @@ public: string newname = copy.fileName(); FileRef *f = new FileRef(newname.c_str()); + CPPUNIT_ASSERT(f->isValid()); CPPUNIT_ASSERT(!f->isNull()); f->tag()->setArtist("test artist"); f->tag()->setTitle("test title"); @@ -48,6 +49,7 @@ public: delete f; f = new FileRef(newname.c_str()); + CPPUNIT_ASSERT(f->isValid()); CPPUNIT_ASSERT(!f->isNull()); CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("test artist")); CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("test title")); @@ -65,6 +67,7 @@ public: delete f; f = new FileRef(newname.c_str()); + CPPUNIT_ASSERT(f->isValid()); CPPUNIT_ASSERT(!f->isNull()); CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("ttest artist")); CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("ytest title")); @@ -73,6 +76,27 @@ public: CPPUNIT_ASSERT_EQUAL(f->tag()->track(), TagLib::uint(7)); CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2080)); delete f; + + f = new FileRef(newname.c_str()); + CPPUNIT_ASSERT(f->isValid()); + CPPUNIT_ASSERT(!f->isNull()); + PropertyMap prop = f->properties(); + CPPUNIT_ASSERT_EQUAL(prop["ARTIST"].front(), String("ttest artist")); + CPPUNIT_ASSERT_EQUAL(prop["TITLE" ].front(), String("ytest title")); + prop["ARTIST"].front() = "a test artist"; + prop["TITLE" ].front() = "b test title"; + f->setProperties(prop); + f->save(); + delete f; + + f = new FileRef(newname.c_str()); + CPPUNIT_ASSERT(f->isValid()); + CPPUNIT_ASSERT(!f->isNull()); + prop = f->properties(); + CPPUNIT_ASSERT_EQUAL(prop["ARTIST"].front(), String("a test artist")); + CPPUNIT_ASSERT_EQUAL(prop["TITLE" ].front(), String("b test title")); + delete f; + } void testMusepack() From ca48435ab67c5d32ab21e58d0697be59e3208739 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sun, 19 May 2013 23:03:15 +0900 Subject: [PATCH 09/10] Moved somethings from global to anonymous namespace. --- taglib/ape/apetag.cpp | 19 +- taglib/asf/asffile.cpp | 25 +- taglib/asf/asftag.cpp | 83 +-- taglib/mp4/mp4tag.cpp | 99 ++-- taglib/mpc/mpcproperties.cpp | 55 +- taglib/mpeg/id3v1/id3v1tag.cpp | 6 +- .../mpeg/id3v2/frames/relativevolumeframe.cpp | 25 +- .../id3v2/frames/textidentificationframe.cpp | 21 +- taglib/mpeg/id3v2/id3v2frame.cpp | 224 +++---- taglib/mpeg/id3v2/id3v2tag.cpp | 6 +- taglib/riff/rifffile.cpp | 32 +- taglib/riff/wav/infotag.cpp | 6 +- taglib/toolkit/tbytevectorlist.cpp | 5 - taglib/wavpack/wavpackproperties.cpp | 5 +- taglib/xm/xmfile.cpp | 558 +++++++++--------- 15 files changed, 607 insertions(+), 562 deletions(-) diff --git a/taglib/ape/apetag.cpp b/taglib/ape/apetag.cpp index dd6095b1..3352a5f9 100644 --- a/taglib/ape/apetag.cpp +++ b/taglib/ape/apetag.cpp @@ -175,14 +175,17 @@ void APE::Tag::setTrack(uint i) addValue("TRACK", String::number(i), true); } -// conversions of tag keys between what we use in PropertyMap and what's usual -// for APE tags -static const TagLib::uint keyConversionsSize = 5; //usual, APE -static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" }, - {"DATE", "YEAR" }, - {"ALBUMARTIST", "ALBUM ARTIST"}, - {"DISCNUMBER", "DISC" }, - {"REMIXER", "MIXARTIST" }}; +namespace +{ + // conversions of tag keys between what we use in PropertyMap and what's usual + // for APE tags + static const TagLib::uint keyConversionsSize = 5; //usual, APE + static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" }, + {"DATE", "YEAR" }, + {"ALBUMARTIST", "ALBUM ARTIST"}, + {"DISCNUMBER", "DISC" }, + {"REMIXER", "MIXARTIST" }}; +} PropertyMap APE::Tag::properties() const { diff --git a/taglib/asf/asffile.cpp b/taglib/asf/asffile.cpp index b09fc887..4ea7822c 100644 --- a/taglib/asf/asffile.cpp +++ b/taglib/asf/asffile.cpp @@ -56,17 +56,20 @@ public: ASF::File::MetadataLibraryObject *metadataLibraryObject; }; -static const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); -static const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16); -static const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16); -static const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); -static const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16); -static const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16); -static const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16); -static const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16); -static const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16); -static const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16); -static const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16); +namespace +{ + const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); + const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16); + const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16); + const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); + const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16); + const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16); + const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16); + const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16); + const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16); + const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16); + const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16); +} class ASF::File::BaseObject { diff --git a/taglib/asf/asftag.cpp b/taglib/asf/asftag.cpp index 0767817f..0132ba69 100644 --- a/taglib/asf/asftag.cpp +++ b/taglib/asf/asftag.cpp @@ -194,46 +194,49 @@ bool ASF::Tag::isEmpty() const d->attributeListMap.isEmpty(); } -static const char *keyTranslation[][2] = { - { "WM/AlbumTitle", "ALBUM" }, - { "WM/Composer", "COMPOSER" }, - { "WM/Writer", "WRITER" }, - { "WM/Conductor", "CONDUCTOR" }, - { "WM/ModifiedBy", "REMIXER" }, - { "WM/Year", "DATE" }, - { "WM/OriginalReleaseYear", "ORIGINALDATE" }, - { "WM/Producer", "PRODUCER" }, - { "WM/ContentGroupDescription", "GROUPING" }, - { "WM/SubTitle", "SUBTITLE" }, - { "WM/SetSubTitle", "DISCSUBTITLE" }, - { "WM/TrackNumber", "TRACKNUMBER" }, - { "WM/PartOfSet", "DISCNUMBER" }, - { "WM/Genre", "GENRE" }, - { "WM/BeatsPerMinute", "BPM" }, - { "WM/Mood", "MOOD" }, - { "WM/ISRC", "ISRC" }, - { "WM/Lyrics", "LYRICS" }, - { "WM/Media", "MEDIA" }, - { "WM/Publisher", "LABEL" }, - { "WM/CatalogNo", "CATALOGNUMBER" }, - { "WM/Barcode", "BARCODE" }, - { "WM/EncodedBy", "ENCODEDBY" }, - { "WM/AlbumSortOrder", "ALBUMSORT" }, - { "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" }, - { "WM/ArtistSortOrder", "ARTISTSORT" }, - { "WM/TitleSortOrder", "TITLESORT" }, - { "WM/Script", "SCRIPT" }, - { "WM/Language", "LANGUAGE" }, - { "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" }, - { "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" }, - { "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" }, - { "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, - { "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, - { "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" }, - { "MusicIP/PUID", "MUSICIP_PUID" }, - { "Acoustid/Id", "ACOUSTID_ID" }, - { "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" }, -}; +namespace +{ + const char *keyTranslation[][2] = { + { "WM/AlbumTitle", "ALBUM" }, + { "WM/Composer", "COMPOSER" }, + { "WM/Writer", "WRITER" }, + { "WM/Conductor", "CONDUCTOR" }, + { "WM/ModifiedBy", "REMIXER" }, + { "WM/Year", "DATE" }, + { "WM/OriginalReleaseYear", "ORIGINALDATE" }, + { "WM/Producer", "PRODUCER" }, + { "WM/ContentGroupDescription", "GROUPING" }, + { "WM/SubTitle", "SUBTITLE" }, + { "WM/SetSubTitle", "DISCSUBTITLE" }, + { "WM/TrackNumber", "TRACKNUMBER" }, + { "WM/PartOfSet", "DISCNUMBER" }, + { "WM/Genre", "GENRE" }, + { "WM/BeatsPerMinute", "BPM" }, + { "WM/Mood", "MOOD" }, + { "WM/ISRC", "ISRC" }, + { "WM/Lyrics", "LYRICS" }, + { "WM/Media", "MEDIA" }, + { "WM/Publisher", "LABEL" }, + { "WM/CatalogNo", "CATALOGNUMBER" }, + { "WM/Barcode", "BARCODE" }, + { "WM/EncodedBy", "ENCODEDBY" }, + { "WM/AlbumSortOrder", "ALBUMSORT" }, + { "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" }, + { "WM/ArtistSortOrder", "ARTISTSORT" }, + { "WM/TitleSortOrder", "TITLESORT" }, + { "WM/Script", "SCRIPT" }, + { "WM/Language", "LANGUAGE" }, + { "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" }, + { "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" }, + { "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" }, + { "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, + { "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, + { "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" }, + { "MusicIP/PUID", "MUSICIP_PUID" }, + { "Acoustid/Id", "ACOUSTID_ID" }, + { "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" }, + }; +} PropertyMap ASF::Tag::properties() const { diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index e5df102f..57bf9dc0 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -767,54 +767,57 @@ MP4::Tag::toString() const return desc.toString("\n"); } -static const char *keyTranslation[][2] = { - { "\251nam", "TITLE" }, - { "\251ART", "ARTIST" }, - { "\251alb", "ALBUM" }, - { "\251cmt", "COMMENT" }, - { "\251gen", "GENRE" }, - { "\251day", "DATE" }, - { "\251wrt", "COMPOSER" }, - { "\251grp", "GROUPING" }, - { "trkn", "TRACKNUMBER" }, - { "disk", "DISCNUMBER" }, - { "cpil", "COMPILATION" }, - { "tmpo", "BPM" }, - { "cprt", "COPYRIGHT" }, - { "\251lyr", "LYRICS" }, - { "\251too", "ENCODEDBY" }, - { "soal", "ALBUMSORT" }, - { "soaa", "ALBUMARTISTSORT" }, - { "soar", "ARTISTSORT" }, - { "sonm", "TITLESORT" }, - { "soco", "COMPOSERSORT" }, - { "sosn", "SHOWSORT" }, - { "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" }, - { "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, - { "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, - { "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, - { "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, - { "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, - { "----:com.apple.iTunes:ASIN", "ASIN" }, - { "----:com.apple.iTunes:LABEL", "LABEL" }, - { "----:com.apple.iTunes:LYRICIST", "LYRICIST" }, - { "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" }, - { "----:com.apple.iTunes:REMIXER", "REMIXER" }, - { "----:com.apple.iTunes:ENGINEER", "ENGINEER" }, - { "----:com.apple.iTunes:PRODUCER", "PRODUCER" }, - { "----:com.apple.iTunes:DJMIXER", "DJMIXER" }, - { "----:com.apple.iTunes:MIXER", "MIXER" }, - { "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" }, - { "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" }, - { "----:com.apple.iTunes:MOOD", "MOOD" }, - { "----:com.apple.iTunes:ISRC", "ISRC" }, - { "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" }, - { "----:com.apple.iTunes:BARCODE", "BARCODE" }, - { "----:com.apple.iTunes:SCRIPT", "SCRIPT" }, - { "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" }, - { "----:com.apple.iTunes:LICENSE", "LICENSE" }, - { "----:com.apple.iTunes:MEDIA", "MEDIA" }, -}; +namespace +{ + const char *keyTranslation[][2] = { + { "\251nam", "TITLE" }, + { "\251ART", "ARTIST" }, + { "\251alb", "ALBUM" }, + { "\251cmt", "COMMENT" }, + { "\251gen", "GENRE" }, + { "\251day", "DATE" }, + { "\251wrt", "COMPOSER" }, + { "\251grp", "GROUPING" }, + { "trkn", "TRACKNUMBER" }, + { "disk", "DISCNUMBER" }, + { "cpil", "COMPILATION" }, + { "tmpo", "BPM" }, + { "cprt", "COPYRIGHT" }, + { "\251lyr", "LYRICS" }, + { "\251too", "ENCODEDBY" }, + { "soal", "ALBUMSORT" }, + { "soaa", "ALBUMARTISTSORT" }, + { "soar", "ARTISTSORT" }, + { "sonm", "TITLESORT" }, + { "soco", "COMPOSERSORT" }, + { "sosn", "SHOWSORT" }, + { "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" }, + { "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, + { "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, + { "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, + { "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, + { "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, + { "----:com.apple.iTunes:ASIN", "ASIN" }, + { "----:com.apple.iTunes:LABEL", "LABEL" }, + { "----:com.apple.iTunes:LYRICIST", "LYRICIST" }, + { "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" }, + { "----:com.apple.iTunes:REMIXER", "REMIXER" }, + { "----:com.apple.iTunes:ENGINEER", "ENGINEER" }, + { "----:com.apple.iTunes:PRODUCER", "PRODUCER" }, + { "----:com.apple.iTunes:DJMIXER", "DJMIXER" }, + { "----:com.apple.iTunes:MIXER", "MIXER" }, + { "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" }, + { "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" }, + { "----:com.apple.iTunes:MOOD", "MOOD" }, + { "----:com.apple.iTunes:ISRC", "ISRC" }, + { "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" }, + { "----:com.apple.iTunes:BARCODE", "BARCODE" }, + { "----:com.apple.iTunes:SCRIPT", "SCRIPT" }, + { "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" }, + { "----:com.apple.iTunes:LICENSE", "LICENSE" }, + { "----:com.apple.iTunes:MEDIA", "MEDIA" }, + }; +} PropertyMap MP4::Tag::properties() const { diff --git a/taglib/mpc/mpcproperties.cpp b/taglib/mpc/mpcproperties.cpp index 64d845ef..0dd4f969 100644 --- a/taglib/mpc/mpcproperties.cpp +++ b/taglib/mpc/mpcproperties.cpp @@ -157,36 +157,39 @@ int MPC::AudioProperties::albumPeak() const // private members //////////////////////////////////////////////////////////////////////////////// -unsigned long readSize(File *file, size_t &sizelength) +namespace { - unsigned char tmp; - unsigned long size = 0; + unsigned long readSize(File *file, size_t &sizelength) + { + unsigned char tmp; + unsigned long size = 0; - do { - ByteVector b = file->readBlock(1); - tmp = b[0]; - size = (size << 7) | (tmp & 0x7F); - sizelength++; - } while((tmp & 0x80)); - return size; + do { + ByteVector b = file->readBlock(1); + tmp = b[0]; + size = (size << 7) | (tmp & 0x7F); + sizelength++; + } while((tmp & 0x80)); + return size; + } + + unsigned long readSize(const ByteVector &data, size_t &sizelength) + { + unsigned char tmp; + unsigned long size = 0; + unsigned long pos = 0; + + do { + tmp = data[pos++]; + size = (size << 7) | (tmp & 0x7F); + sizelength++; + } while((tmp & 0x80) && (pos < data.size())); + return size; + } + + static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 }; } -unsigned long readSize(const ByteVector &data, size_t &sizelength) -{ - unsigned char tmp; - unsigned long size = 0; - unsigned long pos = 0; - - do { - tmp = data[pos++]; - size = (size << 7) | (tmp & 0x7F); - sizelength++; - } while((tmp & 0x80) && (pos < data.size())); - return size; -} - -static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 }; - void MPC::AudioProperties::readSV8(File *file) { bool readSH = false, readRG = false; diff --git a/taglib/mpeg/id3v1/id3v1tag.cpp b/taglib/mpeg/id3v1/id3v1tag.cpp index 4ea3a480..bcb773c3 100644 --- a/taglib/mpeg/id3v1/id3v1tag.cpp +++ b/taglib/mpeg/id3v1/id3v1tag.cpp @@ -51,7 +51,11 @@ public: static const TagLib::StringHandler *stringHandler; }; -static const ID3v1::StringHandler defaultStringHandler; +namespace +{ + const ID3v1::StringHandler defaultStringHandler; +} + const TagLib::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler; //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp b/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp index d95420f5..9981bd4a 100644 --- a/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp +++ b/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp @@ -31,20 +31,23 @@ using namespace TagLib; using namespace ID3v2; -static inline int bitsToBytes(int i) +namespace { - return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1; + static inline int bitsToBytes(int i) + { + return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1; + } + + struct ChannelData + { + ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} + + RelativeVolumeFrame::ChannelType channelType; + short volumeAdjustment; + RelativeVolumeFrame::PeakVolume peakVolume; + }; } -struct ChannelData -{ - ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} - - RelativeVolumeFrame::ChannelType channelType; - short volumeAdjustment; - RelativeVolumeFrame::PeakVolume peakVolume; -}; - class RelativeVolumeFrame::RelativeVolumeFramePrivate { public: diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp index 2849a873..521355db 100644 --- a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -119,15 +119,18 @@ void TextIdentificationFrame::setTextEncoding(String::Type encoding) d->textEncoding = encoding; } -// array of allowed TIPL prefixes and their corresponding key value -static const TagLib::uint involvedPeopleSize = 5; -static const char* involvedPeople[][2] = { - {"ARRANGER", "ARRANGER"}, - {"ENGINEER", "ENGINEER"}, - {"PRODUCER", "PRODUCER"}, - {"DJ-MIX", "DJMIXER"}, - {"MIX", "MIXER"}, -}; +namespace +{ + // array of allowed TIPL prefixes and their corresponding key value + static const TagLib::uint involvedPeopleSize = 5; + static const char* involvedPeople[][2] = { + {"ARRANGER", "ARRANGER"}, + {"ENGINEER", "ENGINEER"}, + {"PRODUCER", "PRODUCER"}, + {"DJ-MIX", "DJMIXER"}, + {"MIX", "MIXER"}, + }; +} const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static { diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index ad015e43..639d9673 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -319,121 +319,125 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc return checkEncoding(fields, encoding, header()->version()); } -static const TagLib::uint frameTranslationSize = 51; -static const char *frameTranslation[][2] = { - // Text information frames - { "TALB", "ALBUM"}, - { "TBPM", "BPM" }, - { "TCOM", "COMPOSER" }, - { "TCON", "GENRE" }, - { "TCOP", "COPYRIGHT" }, - { "TDEN", "ENCODINGTIME" }, - { "TDLY", "PLAYLISTDELAY" }, - { "TDOR", "ORIGINALDATE" }, - { "TDRC", "DATE" }, - // { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - { "TDRL", "RELEASEDATE" }, - { "TDTG", "TAGGINGDATE" }, - { "TENC", "ENCODEDBY" }, - { "TEXT", "LYRICIST" }, - { "TFLT", "FILETYPE" }, - //{ "TIPL", "INVOLVEDPEOPLE" }, handled separately - { "TIT1", "CONTENTGROUP" }, - { "TIT2", "TITLE"}, - { "TIT3", "SUBTITLE" }, - { "TKEY", "INITIALKEY" }, - { "TLAN", "LANGUAGE" }, - { "TLEN", "LENGTH" }, - //{ "TMCL", "MUSICIANCREDITS" }, handled separately - { "TMED", "MEDIA" }, - { "TMOO", "MOOD" }, - { "TOAL", "ORIGINALALBUM" }, - { "TOFN", "ORIGINALFILENAME" }, - { "TOLY", "ORIGINALLYRICIST" }, - { "TOPE", "ORIGINALARTIST" }, - { "TOWN", "OWNER" }, - { "TPE1", "ARTIST"}, - { "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST' - { "TPE3", "CONDUCTOR" }, - { "TPE4", "REMIXER" }, // could also be ARRANGER - { "TPOS", "DISCNUMBER" }, - { "TPRO", "PRODUCEDNOTICE" }, - { "TPUB", "LABEL" }, - { "TRCK", "TRACKNUMBER" }, - { "TRSN", "RADIOSTATION" }, - { "TRSO", "RADIOSTATIONOWNER" }, - { "TSOA", "ALBUMSORT" }, - { "TSOP", "ARTISTSORT" }, - { "TSOT", "TITLESORT" }, - { "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes - { "TSRC", "ISRC" }, - { "TSSE", "ENCODING" }, - // URL frames - { "WCOP", "COPYRIGHTURL" }, - { "WOAF", "FILEWEBPAGE" }, - { "WOAR", "ARTISTWEBPAGE" }, - { "WOAS", "AUDIOSOURCEWEBPAGE" }, - { "WORS", "RADIOSTATIONWEBPAGE" }, - { "WPAY", "PAYMENTWEBPAGE" }, - { "WPUB", "PUBLISHERWEBPAGE" }, - //{ "WXXX", "URL"}, handled specially - // Other frames - { "COMM", "COMMENT" }, - //{ "USLT", "LYRICS" }, handled specially -}; - -static const TagLib::uint txxxFrameTranslationSize = 7; -static const char *txxxFrameTranslation[][2] = { - { "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, - { "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, - { "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, - { "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, - { "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, - { "Acoustid Id", "ACOUSTID_ID" }, - { "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" }, - { "MusicIP PUID", "MUSICIP_PUID" }, -}; - -Map &idMap() +namespace { - static Map m; - if(m.isEmpty()) - for(size_t i = 0; i < frameTranslationSize; ++i) - m[frameTranslation[i][0]] = frameTranslation[i][1]; - return m; -} + static const TagLib::uint frameTranslationSize = 51; + static const char *frameTranslation[][2] = { + // Text information frames + { "TALB", "ALBUM"}, + { "TBPM", "BPM" }, + { "TCOM", "COMPOSER" }, + { "TCON", "GENRE" }, + { "TCOP", "COPYRIGHT" }, + { "TDEN", "ENCODINGTIME" }, + { "TDLY", "PLAYLISTDELAY" }, + { "TDOR", "ORIGINALDATE" }, + { "TDRC", "DATE" }, + // { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + // { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + // { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + // { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 + { "TDRL", "RELEASEDATE" }, + { "TDTG", "TAGGINGDATE" }, + { "TENC", "ENCODEDBY" }, + { "TEXT", "LYRICIST" }, + { "TFLT", "FILETYPE" }, + //{ "TIPL", "INVOLVEDPEOPLE" }, handled separately + { "TIT1", "CONTENTGROUP" }, + { "TIT2", "TITLE"}, + { "TIT3", "SUBTITLE" }, + { "TKEY", "INITIALKEY" }, + { "TLAN", "LANGUAGE" }, + { "TLEN", "LENGTH" }, + //{ "TMCL", "MUSICIANCREDITS" }, handled separately + { "TMED", "MEDIA" }, + { "TMOO", "MOOD" }, + { "TOAL", "ORIGINALALBUM" }, + { "TOFN", "ORIGINALFILENAME" }, + { "TOLY", "ORIGINALLYRICIST" }, + { "TOPE", "ORIGINALARTIST" }, + { "TOWN", "OWNER" }, + { "TPE1", "ARTIST"}, + { "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST' + { "TPE3", "CONDUCTOR" }, + { "TPE4", "REMIXER" }, // could also be ARRANGER + { "TPOS", "DISCNUMBER" }, + { "TPRO", "PRODUCEDNOTICE" }, + { "TPUB", "LABEL" }, + { "TRCK", "TRACKNUMBER" }, + { "TRSN", "RADIOSTATION" }, + { "TRSO", "RADIOSTATIONOWNER" }, + { "TSOA", "ALBUMSORT" }, + { "TSOP", "ARTISTSORT" }, + { "TSOT", "TITLESORT" }, + { "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes + { "TSRC", "ISRC" }, + { "TSSE", "ENCODING" }, + // URL frames + { "WCOP", "COPYRIGHTURL" }, + { "WOAF", "FILEWEBPAGE" }, + { "WOAR", "ARTISTWEBPAGE" }, + { "WOAS", "AUDIOSOURCEWEBPAGE" }, + { "WORS", "RADIOSTATIONWEBPAGE" }, + { "WPAY", "PAYMENTWEBPAGE" }, + { "WPUB", "PUBLISHERWEBPAGE" }, + //{ "WXXX", "URL"}, handled specially + // Other frames + { "COMM", "COMMENT" }, + //{ "USLT", "LYRICS" }, handled specially + }; -Map &txxxMap() -{ - static Map m; - if(m.isEmpty()) { - for(size_t i = 0; i < txxxFrameTranslationSize; ++i) { - String key = String(txxxFrameTranslation[i][0]).upper(); - m[key] = txxxFrameTranslation[i][1]; - } + static const TagLib::uint txxxFrameTranslationSize = 7; + static const char *txxxFrameTranslation[][2] = { + { "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, + { "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, + { "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, + { "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, + { "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, + { "Acoustid Id", "ACOUSTID_ID" }, + { "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" }, + { "MusicIP PUID", "MUSICIP_PUID" }, + }; + + Map &idMap() + { + static Map m; + if(m.isEmpty()) + for(size_t i = 0; i < frameTranslationSize; ++i) + m[frameTranslation[i][0]] = frameTranslation[i][1]; + return m; } - return m; -} -// list of deprecated frames and their successors -static const TagLib::uint deprecatedFramesSize = 4; -static const char *deprecatedFrames[][2] = { - {"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3) - {"TDAT", "TDRC"}, // 2.3 -> 2.4 - {"TYER", "TDRC"}, // 2.3 -> 2.4 - {"TIME", "TDRC"}, // 2.3 -> 2.4 -}; + Map &txxxMap() + { + static Map m; + if(m.isEmpty()) { + for(size_t i = 0; i < txxxFrameTranslationSize; ++i) { + String key = String(txxxFrameTranslation[i][0]).upper(); + m[key] = txxxFrameTranslation[i][1]; + } + } + return m; + } -Map &deprecationMap() -{ - static Map depMap; - if(depMap.isEmpty()) - for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i) - depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1]; - return depMap; + // list of deprecated frames and their successors + static const TagLib::uint deprecatedFramesSize = 4; + static const char *deprecatedFrames[][2] = { + {"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3) + {"TDAT", "TDRC"}, // 2.3 -> 2.4 + {"TYER", "TDRC"}, // 2.3 -> 2.4 + {"TIME", "TDRC"}, // 2.3 -> 2.4 + }; + + + Map &deprecationMap() + { + static Map depMap; + if(depMap.isEmpty()) + for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i) + depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1]; + return depMap; + } } String Frame::frameIDToKey(const ByteVector &id) diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index 5587db35..efd629af 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -74,7 +74,11 @@ public: static const TagLib::StringHandler *stringHandler; }; -static const ID3v2::Latin1StringHandler defaultStringHandler; +namespace +{ + const ID3v2::Latin1StringHandler defaultStringHandler; +} + const TagLib::StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler; //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index 86670c69..cd18a2b0 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -32,13 +32,16 @@ using namespace TagLib; -struct Chunk +namespace { - ByteVector name; - offset_t offset; - TagLib::uint size; - char padding; -}; + struct Chunk + { + ByteVector name; + offset_t offset; + TagLib::uint size; + char padding; + }; +} class RIFF::File::FilePrivate { @@ -250,17 +253,20 @@ void RIFF::File::removeChunk(const ByteVector &name) // private members //////////////////////////////////////////////////////////////////////////////// -static bool isValidChunkID(const ByteVector &name) +namespace { - if(name.size() != 4) { - return false; - } - for(int i = 0; i < 4; i++) { - if(name[i] < 32 || name[i] > 127) { + bool isValidChunkID(const ByteVector &name) + { + if(name.size() != 4) { return false; } + for(int i = 0; i < 4; i++) { + if(name[i] < 32 || name[i] > 127) { + return false; + } + } + return true; } - return true; } void RIFF::File::read() diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index d823b969..f0389154 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -57,7 +57,11 @@ public: static const TagLib::StringHandler *stringHandler; }; -static const RIFF::Info::StringHandler defaultStringHandler; +namespace +{ + const RIFF::Info::StringHandler defaultStringHandler; +} + const TagLib::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler; //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tbytevectorlist.cpp b/taglib/toolkit/tbytevectorlist.cpp index d0d89b4c..02d22f86 100644 --- a/taglib/toolkit/tbytevectorlist.cpp +++ b/taglib/toolkit/tbytevectorlist.cpp @@ -27,11 +27,6 @@ using namespace TagLib; -class ByteVectorListPrivate -{ - -}; - //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/wavpack/wavpackproperties.cpp b/taglib/wavpack/wavpackproperties.cpp index 0ddbab1e..a66f8574 100644 --- a/taglib/wavpack/wavpackproperties.cpp +++ b/taglib/wavpack/wavpackproperties.cpp @@ -120,8 +120,11 @@ TagLib::uint WavPack::AudioProperties::sampleFrames() const // private members //////////////////////////////////////////////////////////////////////////////// -static const unsigned int sample_rates[] = { 6000, 8000, 9600, 11025, 12000, +namespace +{ + const unsigned int sample_rates[] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 }; +} #define BYTES_STORED 3 #define MONO_FLAG 4 diff --git a/taglib/xm/xmfile.cpp b/taglib/xm/xmfile.cpp index 4d9d7f32..f2493b9d 100644 --- a/taglib/xm/xmfile.cpp +++ b/taglib/xm/xmfile.cpp @@ -62,294 +62,298 @@ using TagLib::ushort; * Maybe if this is useful to other formats these classes can be moved to * their own public files. */ -class Reader + +namespace { -public: - virtual ~Reader() + class Reader { - } - - /*! - * Reads associated values from \a file, but never reads more - * then \a limit bytes. - */ - virtual uint read(TagLib::File &file, uint limit) = 0; - - /*! - * Returns the number of bytes this reader would like to read. - */ - virtual uint size() const = 0; -}; - -class SkipReader : public Reader -{ -public: - SkipReader(uint size) : m_size(size) - { - } - - uint read(TagLib::File &file, uint limit) - { - uint count = std::min(m_size, limit); - file.seek(count, TagLib::File::Current); - return count; - } - - uint size() const - { - return m_size; - } - -private: - uint m_size; -}; - -template -class ValueReader : public Reader -{ -public: - ValueReader(T &value) : value(value) - { - } - -protected: - T &value; -}; - -class StringReader : public ValueReader -{ -public: - StringReader(String &string, uint size) : - ValueReader(string), m_size(size) - { - } - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(m_size, limit)); - size_t count = data.size(); - const size_t index = data.find((char) 0); - if(index != ByteVector::npos) { - data.resize(index); + public: + virtual ~Reader() + { } - data.replace((char) 0xff, ' '); - value = data; - return static_cast(count); - } - uint size() const + /*! + * Reads associated values from \a file, but never reads more + * then \a limit bytes. + */ + virtual uint read(TagLib::File &file, uint limit) = 0; + + /*! + * Returns the number of bytes this reader would like to read. + */ + virtual uint size() const = 0; + }; + + class SkipReader : public Reader { - return m_size; - } - -private: - uint m_size; -}; - -class ByteReader : public ValueReader -{ -public: - ByteReader(uchar &byte) : ValueReader(byte) {} - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(1U,limit)); - if(data.size() > 0) { - value = data[0]; + public: + SkipReader(uint size) : m_size(size) + { } - return static_cast(data.size()); - } - uint size() const - { - return 1; - } -}; - -template -class NumberReader : public ValueReader -{ -public: - NumberReader(T &value, bool bigEndian) : - ValueReader(value), bigEndian(bigEndian) - { - } - -protected: - bool bigEndian; -}; - -class U16Reader : public NumberReader -{ -public: - U16Reader(ushort &value, bool bigEndian) - : NumberReader(value, bigEndian) {} - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(2U,limit)); - - if(bigEndian) - value = data.toUInt16BE(0); - else - value = data.toUInt16LE(0); - - return static_cast(data.size()); - } - - uint size() const - { - return 2; - } -}; - -class U32Reader : public NumberReader -{ -public: - U32Reader(uint &value, bool bigEndian = true) : - NumberReader(value, bigEndian) - { - } - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(4U,limit)); - - if(bigEndian) - value = data.toUInt32BE(0); - else - value = data.toUInt32LE(0); - - return static_cast(data.size()); - } - - uint size() const - { - return 4; - } -}; - -class StructReader : public Reader -{ -public: - StructReader() - { - m_readers.setAutoDelete(true); - } - - /*! - * Add a nested reader. This reader takes ownership. - */ - StructReader &reader(Reader *reader) - { - m_readers.append(reader); - return *this; - } - - /*! - * Don't read anything but skip \a size bytes. - */ - StructReader &skip(uint size) - { - m_readers.append(new SkipReader(size)); - return *this; - } - - /*! - * Read a string of \a size characters (bytes) into \a string. - */ - StructReader &string(String &string, uint size) - { - m_readers.append(new StringReader(string, size)); - return *this; - } - - /*! - * Read a byte into \a byte. - */ - StructReader &byte(uchar &byte) - { - m_readers.append(new ByteReader(byte)); - return *this; - } - - /*! - * Read a unsigned 16 Bit integer into \a number. The byte order - * is controlled by \a bigEndian. - */ - StructReader &u16(ushort &number, bool bigEndian) - { - m_readers.append(new U16Reader(number, bigEndian)); - return *this; - } - - /*! - * Read a unsigned 16 Bit little endian integer into \a number. - */ - StructReader &u16L(ushort &number) - { - return u16(number, false); - } - - /*! - * Read a unsigned 16 Bit big endian integer into \a number. - */ - StructReader &u16B(ushort &number) - { - return u16(number, true); - } - - /*! - * Read a unsigned 32 Bit integer into \a number. The byte order - * is controlled by \a bigEndian. - */ - StructReader &u32(uint &number, bool bigEndian) - { - m_readers.append(new U32Reader(number, bigEndian)); - return *this; - } - - /*! - * Read a unsigned 32 Bit little endian integer into \a number. - */ - StructReader &u32L(uint &number) - { - return u32(number, false); - } - - /*! - * Read a unsigned 32 Bit big endian integer into \a number. - */ - StructReader &u32B(uint &number) - { - return u32(number, true); - } - - uint size() const - { - uint size = 0; - for(List::ConstIterator i = m_readers.begin(); - i != m_readers.end(); ++ i) { - size += (*i)->size(); + uint read(TagLib::File &file, uint limit) + { + uint count = std::min(m_size, limit); + file.seek(count, TagLib::File::Current); + return count; } - return size; - } - uint read(TagLib::File &file, uint limit) - { - uint sumcount = 0; - for(List::Iterator i = m_readers.begin(); - limit > 0 && i != m_readers.end(); ++ i) { - uint count = (*i)->read(file, limit); - limit -= count; - sumcount += count; + uint size() const + { + return m_size; } - return sumcount; - } -private: - List m_readers; -}; + private: + uint m_size; + }; + + template + class ValueReader : public Reader + { + public: + ValueReader(T &value) : value(value) + { + } + + protected: + T &value; + }; + + class StringReader : public ValueReader + { + public: + StringReader(String &string, uint size) : + ValueReader(string), m_size(size) + { + } + + uint read(TagLib::File &file, uint limit) + { + ByteVector data = file.readBlock(std::min(m_size, limit)); + size_t count = data.size(); + const size_t index = data.find((char) 0); + if(index != ByteVector::npos) { + data.resize(index); + } + data.replace((char) 0xff, ' '); + value = data; + return static_cast(count); + } + + uint size() const + { + return m_size; + } + + private: + uint m_size; + }; + + class ByteReader : public ValueReader + { + public: + ByteReader(uchar &byte) : ValueReader(byte) {} + + uint read(TagLib::File &file, uint limit) + { + ByteVector data = file.readBlock(std::min(1U,limit)); + if(data.size() > 0) { + value = data[0]; + } + return static_cast(data.size()); + } + + uint size() const + { + return 1; + } + }; + + template + class NumberReader : public ValueReader + { + public: + NumberReader(T &value, bool bigEndian) : + ValueReader(value), bigEndian(bigEndian) + { + } + + protected: + bool bigEndian; + }; + + class U16Reader : public NumberReader + { + public: + U16Reader(ushort &value, bool bigEndian) + : NumberReader(value, bigEndian) {} + + uint read(TagLib::File &file, uint limit) + { + ByteVector data = file.readBlock(std::min(2U,limit)); + + if(bigEndian) + value = data.toUInt16BE(0); + else + value = data.toUInt16LE(0); + + return static_cast(data.size()); + } + + uint size() const + { + return 2; + } + }; + + class U32Reader : public NumberReader + { + public: + U32Reader(uint &value, bool bigEndian = true) : + NumberReader(value, bigEndian) + { + } + + uint read(TagLib::File &file, uint limit) + { + ByteVector data = file.readBlock(std::min(4U,limit)); + + if(bigEndian) + value = data.toUInt32BE(0); + else + value = data.toUInt32LE(0); + + return static_cast(data.size()); + } + + uint size() const + { + return 4; + } + }; + + class StructReader : public Reader + { + public: + StructReader() + { + m_readers.setAutoDelete(true); + } + + /*! + * Add a nested reader. This reader takes ownership. + */ + StructReader &reader(Reader *reader) + { + m_readers.append(reader); + return *this; + } + + /*! + * Don't read anything but skip \a size bytes. + */ + StructReader &skip(uint size) + { + m_readers.append(new SkipReader(size)); + return *this; + } + + /*! + * Read a string of \a size characters (bytes) into \a string. + */ + StructReader &string(String &string, uint size) + { + m_readers.append(new StringReader(string, size)); + return *this; + } + + /*! + * Read a byte into \a byte. + */ + StructReader &byte(uchar &byte) + { + m_readers.append(new ByteReader(byte)); + return *this; + } + + /*! + * Read a unsigned 16 Bit integer into \a number. The byte order + * is controlled by \a bigEndian. + */ + StructReader &u16(ushort &number, bool bigEndian) + { + m_readers.append(new U16Reader(number, bigEndian)); + return *this; + } + + /*! + * Read a unsigned 16 Bit little endian integer into \a number. + */ + StructReader &u16L(ushort &number) + { + return u16(number, false); + } + + /*! + * Read a unsigned 16 Bit big endian integer into \a number. + */ + StructReader &u16B(ushort &number) + { + return u16(number, true); + } + + /*! + * Read a unsigned 32 Bit integer into \a number. The byte order + * is controlled by \a bigEndian. + */ + StructReader &u32(uint &number, bool bigEndian) + { + m_readers.append(new U32Reader(number, bigEndian)); + return *this; + } + + /*! + * Read a unsigned 32 Bit little endian integer into \a number. + */ + StructReader &u32L(uint &number) + { + return u32(number, false); + } + + /*! + * Read a unsigned 32 Bit big endian integer into \a number. + */ + StructReader &u32B(uint &number) + { + return u32(number, true); + } + + uint size() const + { + uint size = 0; + for(List::ConstIterator i = m_readers.begin(); + i != m_readers.end(); ++ i) { + size += (*i)->size(); + } + return size; + } + + uint read(TagLib::File &file, uint limit) + { + uint sumcount = 0; + for(List::Iterator i = m_readers.begin(); + limit > 0 && i != m_readers.end(); ++ i) { + uint count = (*i)->read(file, limit); + limit -= count; + sumcount += count; + } + return sumcount; + } + + private: + List m_readers; + }; +} class XM::File::FilePrivate { From 848f8c316e3bfd1210f44d26a26780b09b496083 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 21 May 2013 05:36:01 +0900 Subject: [PATCH 10/10] Changed behavior of ByteVector::toNumber() when overrun --- taglib/toolkit/tbytevector.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index b3c8897f..84d3f004 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -299,10 +299,8 @@ ulonglong byteSwap(ulonglong x) template T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) { - if(offset + sizeof(T) > v.size()) { - debug("toNumber() -- offset is out of range. Returning 0."); - return 0; - } + if(offset + sizeof(T) > v.size()) + return toNumber(v, offset, v.size() - offset, mostSignificantByteFirst); // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. T tmp; @@ -322,11 +320,13 @@ T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) 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."); + if(offset >= v.size()) { + debug("toNumber() -- No data to convert. Returning 0."); return 0; } + length = std::min(length, v.size() - offset); + T sum = 0; for(size_t i = 0; i < length; i++) { const size_t shift = (mostSignificantByteFirst ? length - 1 - i : i) * 8;