diff --git a/bindings/c/tag_c.h b/bindings/c/tag_c.h index ab5dd202..2e8b752f 100644 --- a/bindings/c/tag_c.h +++ b/bindings/c/tag_c.h @@ -29,7 +29,9 @@ extern "C" { #endif -#if defined(_WIN32) || defined(_WIN64) +#if defined(TAGLIB_STATIC) +#define TAGLIB_C_EXPORT +#elif defined(_WIN32) || defined(_WIN64) #ifdef MAKE_TAGLIB_C_LIB #define TAGLIB_C_EXPORT __declspec(dllexport) #else diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index e582eb2c..0a2676bd 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -51,6 +51,7 @@ set(tag_HDRS toolkit/tmap.h toolkit/tmap.tcc toolkit/tpropertymap.h + toolkit/tbyteswap.h mpeg/mpegfile.h mpeg/mpegproperties.h mpeg/mpegheader.h @@ -291,6 +292,7 @@ set(toolkit_SRCS toolkit/tfilestream.cpp toolkit/tdebug.cpp toolkit/tpropertymap.cpp + toolkit/tbyteswap.cpp toolkit/unicode.cpp ) diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index c10dbb86..7b3629a4 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -186,7 +186,7 @@ MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - d->items.insert(atom->name, (uchar)data[0].at(0)); + addItem(atom->name, (uchar)data[0].at(0)); } } @@ -195,7 +195,7 @@ MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - int idx = (int)data[0].toInt16(); + const int idx = (int)data[0].toInt16(); if(!d->items.contains("\251gen") && idx > 0) { d->items.insert("\251gen", StringList(ID3v1::genre(idx - 1))); } @@ -207,8 +207,8 @@ MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - int a = data[0].mid(2, 2).toInt16(); - int b = data[0].mid(4, 2).toInt16(); + const int a = data[0].mid(2, 2).toInt16(); + const int b = data[0].mid(4, 2).toInt16(); d->items.insert(atom->name, MP4::Item(a, b)); } } @@ -219,7 +219,7 @@ MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file) ByteVectorList data = parseData(atom, file); if(data.size()) { bool value = data[0].size() ? data[0][0] != '\0' : false; - d->items.insert(atom->name, value); + addItem(atom->name, value); } } @@ -232,7 +232,7 @@ MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags) for(unsigned int i = 0; i < data.size(); i++) { value.append(String(data[i], String::UTF8)); } - d->items.insert(atom->name, value); + addItem(atom->name, value); } } @@ -256,7 +256,7 @@ MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file) } Item item(value); item.setAtomDataType(type); - d->items.insert(name, item); + addItem(name, item); } else { ByteVectorList value; @@ -265,7 +265,7 @@ MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file) } Item item(value); item.setAtomDataType(type); - d->items.insert(name, item); + addItem(name, item); } } } @@ -294,7 +294,7 @@ MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) pos += length; } if(value.size() > 0) - d->items.insert(atom->name, value); + addItem(atom->name, value); } ByteVector @@ -920,3 +920,12 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props) return ignoredProps; } +void MP4::Tag::addItem(const String &name, const Item &value) +{ + if(!d->items.contains(name)) { + d->items.insert(name, value); + } + else { + debug("MP4: Ignoring duplicate atom \"" + name + "\""); + } +} diff --git a/taglib/mp4/mp4tag.h b/taglib/mp4/mp4tag.h index da0d68de..c5152a5f 100644 --- a/taglib/mp4/mp4tag.h +++ b/taglib/mp4/mp4tag.h @@ -107,6 +107,8 @@ namespace TagLib { void saveNew(TagLib::ByteVector &data); void saveExisting(TagLib::ByteVector &data, AtomList &path); + void addItem(const String &name, const Item &value); + class TagPrivate; TagPrivate *d; }; diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index 89b1d0af..d57b8234 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -134,7 +134,7 @@ Frame *Frame::createTextualFrame(const String &key, const StringList &values) // // now we check if it's one of the "special" cases: // -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS) if((key == "LYRICS" || key.startsWith(lyricsPrefix)) && values.size() == 1){ - UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame(); + UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame(String::UTF8); frame->setDescription(key == "LYRICS" ? key : key.substr(lyricsPrefix.size())); frame->setText(values.front()); return frame; diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index 2446be56..4743a505 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -153,6 +153,11 @@ bool MPEG::File::save() } bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version) +{ + return save(tags, stripOthers, id3v2Version, true); +} + +bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags) { if(tags == NoTags && stripOthers) return strip(AllTags); @@ -170,14 +175,19 @@ bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version) return false; } - // Create the tags if we've been asked to. Copy the values from the tag that - // does exist into the new tag, except if the existing tag is to be stripped. + // Create the tags if we've been asked to. - if((tags & ID3v2) && ID3v1Tag() && !(stripOthers && !(tags & ID3v1))) - Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false); + if (duplicateTags) { - if((tags & ID3v1) && d->tag[ID3v2Index] && !(stripOthers && !(tags & ID3v2))) - Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false); + // Copy the values from the tag that does exist into the new tag, + // except if the existing tag is to be stripped. + + if((tags & ID3v2) && ID3v1Tag() && !(stripOthers && !(tags & ID3v1))) + Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false); + + if((tags & ID3v1) && d->tag[ID3v2Index] && !(stripOthers && !(tags & ID3v2))) + Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false); + } bool success = true; @@ -616,9 +626,6 @@ void MPEG::File::findAPE() bool MPEG::File::secondSynchByte(char byte) { - if(uchar(byte) == 0xff) - return false; - std::bitset<8> b(byte); // check to see if the byte matches 111xxxxx diff --git a/taglib/mpeg/mpegfile.h b/taglib/mpeg/mpegfile.h index 6bf5ad08..35c9bb5f 100644 --- a/taglib/mpeg/mpegfile.h +++ b/taglib/mpeg/mpegfile.h @@ -179,6 +179,24 @@ namespace TagLib { */ bool save(int tags, bool stripOthers = true, int id3v2Version = 4); + /*! + * Save the file. This will attempt to save all of the tag types that are + * specified by OR-ing together TagTypes values. The save() method above + * uses AllTags. This returns true if saving was successful. + * + * If \a stripOthers is true this strips all tags not included in the mask, + * but does not modify them in memory, so later calls to save() which make + * use of these tags will remain valid. This also strips empty tags. + * + * The \a id3v2Version parameter specifies the version of the saved + * ID3v2 tag. It can be either 4 or 3. + * + * If \a duplicateTags is true and at least one tag -- ID3v1 or ID3v2 -- + * exists this will duplicate its content into the other tag. + */ + // BIC: combine with the above method + bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags); + /*! * Returns a pointer to the ID3v2 tag of the file. * diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index 5f976ef2..e71e5444 100644 --- a/taglib/ogg/flac/oggflacfile.cpp +++ b/taglib/ogg/flac/oggflacfile.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "oggflacfile.h" @@ -94,6 +95,16 @@ Ogg::XiphComment *Ogg::FLAC::File::tag() const return d->comment; } +PropertyMap Ogg::FLAC::File::properties() const +{ + return d->comment->properties(); +} + +PropertyMap Ogg::FLAC::File::setProperties(const PropertyMap &properties) +{ + return d->comment->setProperties(properties); +} + Properties *Ogg::FLAC::File::audioProperties() const { return d->properties; diff --git a/taglib/ogg/flac/oggflacfile.h b/taglib/ogg/flac/oggflacfile.h index 2e08a55c..e1e8d682 100644 --- a/taglib/ogg/flac/oggflacfile.h +++ b/taglib/ogg/flac/oggflacfile.h @@ -92,12 +92,28 @@ namespace TagLib { */ virtual XiphComment *tag() const; + + /*! * Returns the FLAC::Properties for this file. If no audio properties * were read then this will return a null pointer. */ virtual Properties *audioProperties() const; + + /*! + * Implements the unified property interface -- export function. + * This forwards directly to XiphComment::properties(). + */ + PropertyMap properties() const; + + /*! + * Implements the unified tag dictionary interface -- import function. + * Like properties(), this is a forwarder to the file's XiphComment. + */ + PropertyMap setProperties(const PropertyMap &); + + /*! * Save the file. This will primarily save and update the XiphComment. * Returns true if the save is successful. diff --git a/taglib/ogg/opus/opusfile.cpp b/taglib/ogg/opus/opusfile.cpp index ecbc218d..8d3af7af 100644 --- a/taglib/ogg/opus/opusfile.cpp +++ b/taglib/ogg/opus/opusfile.cpp @@ -31,6 +31,7 @@ #include #include +#include #include "opusfile.h" @@ -82,6 +83,16 @@ Ogg::XiphComment *Opus::File::tag() const return d->comment; } +PropertyMap Opus::File::properties() const +{ + return d->comment->properties(); +} + +PropertyMap Opus::File::setProperties(const PropertyMap &properties) +{ + return d->comment->setProperties(properties); +} + Opus::Properties *Opus::File::audioProperties() const { return d->properties; diff --git a/taglib/ogg/opus/opusfile.h b/taglib/ogg/opus/opusfile.h index 73375af8..736235c6 100644 --- a/taglib/ogg/opus/opusfile.h +++ b/taglib/ogg/opus/opusfile.h @@ -86,6 +86,18 @@ namespace TagLib { */ virtual Ogg::XiphComment *tag() const; + /*! + * Implements the unified property interface -- export function. + * This forwards directly to XiphComment::properties(). + */ + PropertyMap properties() const; + + /*! + * Implements the unified tag dictionary interface -- import function. + * Like properties(), this is a forwarder to the file's XiphComment. + */ + PropertyMap setProperties(const PropertyMap &); + /*! * Returns the Opus::Properties for this file. If no audio properties * were read then this will return a null pointer. diff --git a/taglib/ogg/speex/speexfile.cpp b/taglib/ogg/speex/speexfile.cpp index 8ac86e69..e83f0ad9 100644 --- a/taglib/ogg/speex/speexfile.cpp +++ b/taglib/ogg/speex/speexfile.cpp @@ -31,6 +31,7 @@ #include #include +#include #include "speexfile.h" @@ -84,6 +85,16 @@ Ogg::XiphComment *Speex::File::tag() const return d->comment; } +PropertyMap Speex::File::properties() const +{ + return d->comment->properties(); +} + +PropertyMap Speex::File::setProperties(const PropertyMap &properties) +{ + return d->comment->setProperties(properties); +} + Speex::Properties *Speex::File::audioProperties() const { return d->properties; diff --git a/taglib/ogg/speex/speexfile.h b/taglib/ogg/speex/speexfile.h index dfe51ec4..2bbf8f40 100644 --- a/taglib/ogg/speex/speexfile.h +++ b/taglib/ogg/speex/speexfile.h @@ -86,12 +86,26 @@ namespace TagLib { */ virtual Ogg::XiphComment *tag() const; + /*! + * Implements the unified property interface -- export function. + * This forwards directly to XiphComment::properties(). + */ + PropertyMap properties() const; + + /*! + * Implements the unified tag dictionary interface -- import function. + * Like properties(), this is a forwarder to the file's XiphComment. + */ + PropertyMap setProperties(const PropertyMap &); + /*! * Returns the Speex::Properties for this file. If no audio properties * were read then this will return a null pointer. */ virtual Properties *audioProperties() const; + + virtual bool save(); private: diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index ece84f05..19b80c8a 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -90,6 +90,11 @@ PropertyMap RIFF::AIFF::File::properties() const return d->tag->properties(); } +void RIFF::AIFF::File::removeUnsupportedProperties(const StringList &unsupported) +{ + d->tag->removeUnsupportedProperties(unsupported); +} + PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties) { return d->tag->setProperties(properties); diff --git a/taglib/riff/aiff/aifffile.h b/taglib/riff/aiff/aifffile.h index e1284db0..f2ce0ba2 100644 --- a/taglib/riff/aiff/aifffile.h +++ b/taglib/riff/aiff/aifffile.h @@ -92,6 +92,8 @@ namespace TagLib { */ PropertyMap properties() const; + void removeUnsupportedProperties(const StringList &properties); + /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). diff --git a/taglib/riff/wav/wavfile.cpp b/taglib/riff/wav/wavfile.cpp index 0ba40665..43f2d812 100644 --- a/taglib/riff/wav/wavfile.cpp +++ b/taglib/riff/wav/wavfile.cpp @@ -103,12 +103,17 @@ RIFF::Info::Tag *RIFF::WAV::File::InfoTag() const PropertyMap RIFF::WAV::File::properties() const { - return d->tag.properties(); + return tag()->properties(); +} + +void RIFF::WAV::File::removeUnsupportedProperties(const StringList &unsupported) +{ + tag()->removeUnsupportedProperties(unsupported); } PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) { - return d->tag.setProperties(properties); + return tag()->setProperties(properties); } RIFF::WAV::Properties *RIFF::WAV::File::audioProperties() const diff --git a/taglib/riff/wav/wavfile.h b/taglib/riff/wav/wavfile.h index 18ce2336..980f6e4d 100644 --- a/taglib/riff/wav/wavfile.h +++ b/taglib/riff/wav/wavfile.h @@ -117,6 +117,8 @@ namespace TagLib { */ PropertyMap properties() const; + void removeUnsupportedProperties(const StringList &properties); + /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index 987bd0cf..ff6a64f2 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -77,16 +77,28 @@ # endif #endif -// Detect CPU endian at compile time rather than run time if possible. -// This is a poor list. Hope someone enrich it. -#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) \ - || (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) \ - || (defined(__clang__) && (defined(__i386__) || defined(__x86_64__))) -# define TAGLIB_LITTLE_ENDIAN -/* -#elif .... -# define TAGLIB_BIG_ENDIAN -*/ +// Check the widths of integral types. + +#if UCHAR_MAX != 255U +# error TagLib assumes that char is 8-bit wide. +#endif + +#if USHRT_MAX != 65535U +# error TagLib assumes that short is 16-bit wide. +#endif + +#if UINT_MAX != 4294967295U +# error TagLib assumes that int is 32-bit wide. +#endif + +#if !defined(ULLONG_MAX) && !defined(ULONGLONG_MAX) && !defined(ULONG_LONG_MAX) +# error TagLib assumes that long long is 64-bit wide. +#elif defined(ULLONG_MAX) && ULLONG_MAX != 18446744073709551615ULL +# error TagLib assumes that long long is 64-bit wide. +#elif defined(ULONGLONG_MAX) && ULONGLONG_MAX != 18446744073709551615ULL +# error TagLib assumes that long long is 64-bit wide. +#elif defined(ULONG_LONG_MAX) && ULONG_LONG_MAX != 18446744073709551615ULL +# error TagLib assumes that long long is 64-bit wide. #endif // Check the widths of integral types. @@ -127,7 +139,7 @@ namespace TagLib { class String; - typedef wchar_t wchar; + typedef wchar_t wchar; // Assumed to be sufficient to store a UTF-16 char. typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; diff --git a/taglib/toolkit/tbyteswap.cpp b/taglib/toolkit/tbyteswap.cpp new file mode 100644 index 00000000..714033e8 --- /dev/null +++ b/taglib/toolkit/tbyteswap.cpp @@ -0,0 +1,197 @@ +/*************************************************************************** + copyright : (C) 2013 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#include "taglib.h" +#include "tbyteswap.h" + +// Determines if compiler intrinsic functions are available. + +// MSVC: Intrinsic _byteswap_* functions. +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# include +# define TAGLIB_BYTESWAP_MSC + +// GCC 4.8 or above: __builtin_bswap16(), 32 and 64. +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +# define TAGLIB_BYTESWAP_GCC 2 + +// GCC 4.3 or above: __builtin_bswap16 is missing. +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +# define TAGLIB_BYTESWAP_GCC 1 + +#endif + +// Determines if platform or library specific functions are available. + +#if defined(__APPLE__) +# include +# define TAGLIB_BYTESWAP_MAC + +#elif defined(__OpenBSD__) +# include +# define TAGLIB_BYTESWAP_OPENBSD + +#elif defined(__GLIBC__) +# include +# define TAGLIB_BYTESWAP_GLIBC + +#endif + +// Determines CPU byte order at compile time rather than run time if possible. + +#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) \ + || (defined(__GNUC__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \ + || (defined(__clang__) && defined(__LITTLE_ENDIAN__)) +# define TAGLIB_LITTLE_ENDIAN + +#elif (defined(__GNUC__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) \ + || (defined(__clang__) && defined(__BIG_ENDIAN__)) +# define TAGLIB_BIG_ENDIAN + +#else + +namespace { + bool isLittleEndian() + { + TagLib::ushort x = 1; + return (*reinterpret_cast(&x) == 1); + } +} + +#endif + +namespace TagLib +{ + ushort byteSwap16(ushort x) + { +#if defined(TAGLIB_BYTESWAP_MSC) + + return _byteswap_ushort(x); + +#elif defined(TAGLIB_BYTESWAP_GCC) && TAGLIB_BYTESWAP_GCC == 2 + + return __builtin_bswap16(x); + +#elif defined(TAGLIB_BYTESWAP_MAC) + + return OSSwapInt16(x); + +#elif defined(TAGLIB_BYTESWAP_OPENBSD) + + return swap16(x); + +#elif defined(TAGLIB_BYTESWAP_GLIBC) + + return __bswap_16(x); + +#else + + return ((x >> 8) & 0xff) | ((x & 0xff) << 8); + +#endif + } + + uint byteSwap32(uint x) + { +#if defined(TAGLIB_BYTESWAP_MSC) + + return _byteswap_ulong(x); + +#elif defined(TAGLIB_BYTESWAP_GCC) + + return __builtin_bswap32(x); + +#elif defined(TAGLIB_BYTESWAP_MAC) + + return OSSwapInt32(x); + +#elif defined(TAGLIB_BYTESWAP_OPENBSD) + + return swap32(x); + +#elif defined(TAGLIB_BYTESWAP_GLIBC) + + return __bswap_32(x); + +#else + + return ((x & 0xff000000) >> 24) + | ((x & 0x00ff0000) >> 8) + | ((x & 0x0000ff00) << 8) + | ((x & 0x000000ff) << 24); + +#endif + } + + ulonglong byteSwap64(ulonglong x) + { +#if defined(TAGLIB_BYTESWAP_MSC) + + return _byteswap_uint64(x); + +#elif defined(TAGLIB_BYTESWAP_GCC) + + return __builtin_bswap64(x); + +#elif defined(TAGLIB_BYTESWAP_MAC) + + return OSSwapInt64(x); + +#elif defined(TAGLIB_BYTESWAP_OPENBSD) + + return swap64(x); + +#elif defined(TAGLIB_BYTESWAP_GLIBC) + + return __bswap_64(x); + +#else + + return ((x & 0xff00000000000000ull) >> 56) + | ((x & 0x00ff000000000000ull) >> 40) + | ((x & 0x0000ff0000000000ull) >> 24) + | ((x & 0x000000ff00000000ull) >> 8) + | ((x & 0x00000000ff000000ull) << 8) + | ((x & 0x0000000000ff0000ull) << 24) + | ((x & 0x000000000000ff00ull) << 40) + | ((x & 0x00000000000000ffull) << 56); + +#endif + } + +#if defined(TAGLIB_LITTLE_ENDIAN) + + const bool isLittleEndianSystem = true; + +#elif defined(TAGLIB_BIG_ENDIAN) + + const bool isLittleEndianSystem = false; + +#else + + const bool isLittleEndianSystem = isLittleEndianSystem(); + +#endif +} diff --git a/taglib/toolkit/tbyteswap.h b/taglib/toolkit/tbyteswap.h new file mode 100644 index 00000000..012a3173 --- /dev/null +++ b/taglib/toolkit/tbyteswap.h @@ -0,0 +1,55 @@ +/*************************************************************************** + copyright : (C) 2013 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_BYTESWAP_H +#define TAGLIB_BYTESWAP_H + +namespace TagLib +{ + // Cross-platform byte order conversion functions. + + /*! + * Converts the byte order of \a x as a 16-bit unsigned integer. + */ + ushort byteSwap16(ushort x); + + /*! + * Converts the byte order of \a x as a 32-bit unsigned integer. + */ + uint byteSwap32(uint x); + + /*! + * Converts the byte order of \a x as a 64-bit unsigned integer. + */ + ulonglong byteSwap64(ulonglong x); + + /*! + * Indicates the system byte order. + * \a true if little endian, \a false if big endian. + */ + extern const bool isLittleEndianSystem; +} + +#endif diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index c0698c01..5e074750 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -24,10 +24,8 @@ ***************************************************************************/ #include - #include #include - #include #if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(_M_IX86) || defined(_M_X64)) @@ -41,260 +39,212 @@ #endif #include "tbytevector.h" +#include "tbyteswap.h" // This is a bit ugly to keep writing over and over again. // A rather obscure feature of the C++ spec that I hadn't thought of that makes -// working with C libs much more effecient. There's more here: +// working with C libs much more efficient. There's more here: // // http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp #define DATA(x) (&(x->data->data[0])) namespace TagLib { - static const char hexTable[17] = "0123456789abcdef"; - static const uint crcTable[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, - 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, - 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, - 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, - 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, - 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, - 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, - 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, - 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, - 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, - 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, - 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, - 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, - 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, - 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, - 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, - 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, - 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, - 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, - 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, - 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, - 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 - }; +static const char hexTable[17] = "0123456789abcdef"; - /*! - * A templatized straightforward find that works with the types - * std::vector::iterator and std::vector::reverse_iterator. - */ - template - size_t findChar( - const TIterator dataBegin, const TIterator dataEnd, - char c, size_t offset, size_t byteAlign) - { - const size_t dataSize = dataEnd - dataBegin; - if(dataSize == 0 || offset > dataSize - 1) - return ByteVector::npos; - - // n % 0 is invalid - - if(byteAlign == 0) - return ByteVector::npos; - - for(TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { - if(*it == c) - return (it - dataBegin); - } +static const uint crcTable[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; +/*! + * A templatized straightforward find that works with the types + * std::vector::iterator and std::vector::reverse_iterator. + */ +template +size_t findChar( + const TIterator dataBegin, const TIterator dataEnd, + char c, size_t offset, size_t byteAlign) +{ + const size_t dataSize = dataEnd - dataBegin; + if(dataSize == 0 || offset > dataSize - 1) return ByteVector::npos; + + // n % 0 is invalid + + if(byteAlign == 0) + return ByteVector::npos; + + for(TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { + if(*it == c) + return (it - dataBegin); } - /*! - * A templatized KMP find that works with the types - * std::vector::iterator and std::vector::reverse_iterator. - */ - template - size_t findVector( - const TIterator dataBegin, const TIterator dataEnd, - const TIterator patternBegin, const TIterator patternEnd, - size_t offset, size_t byteAlign) + return ByteVector::npos; +} + +/*! + * A templatized KMP find that works with the types + * std::vector::iterator and std::vector::reverse_iterator. + */ +template +size_t findVector( + const TIterator dataBegin, const TIterator dataEnd, + const TIterator patternBegin, const TIterator patternEnd, + size_t offset, size_t byteAlign) +{ + const size_t dataSize = dataEnd - dataBegin; + const size_t patternSize = patternEnd - patternBegin; + if(patternSize > dataSize || offset > dataSize - 1) + return ByteVector::npos; + + // n % 0 is invalid + + if(byteAlign == 0) + return ByteVector::npos; + + // Special case that the pattern contains just single char. + + if(patternSize == 1) + return findChar(dataBegin, dataEnd, *patternBegin, offset, byteAlign); + + size_t lastOccurrence[256]; + + for(size_t i = 0; i < 256; ++i) + lastOccurrence[i] = patternSize; + + for(size_t i = 0; i < patternSize - 1; ++i) + lastOccurrence[static_cast(*(patternBegin + i))] = patternSize - i - 1; + + for(TIterator it = dataBegin + patternSize - 1 + offset; + it < dataEnd; + it += lastOccurrence[static_cast(*it)]) { - const size_t dataSize = dataEnd - dataBegin; - const size_t patternSize = patternEnd - patternBegin; - if(patternSize > dataSize || offset > dataSize - 1) - return ByteVector::npos; + TIterator itBuffer = it; + TIterator itPattern = patternBegin + patternSize - 1; - // n % 0 is invalid - - if(byteAlign == 0) - return ByteVector::npos; - - // Special case that the pattern contains just single char. - - if(patternSize == 1) - return findChar(dataBegin, dataEnd, *patternBegin, offset, byteAlign); - - size_t lastOccurrence[256]; - - for(size_t i = 0; i < 256; ++i) - lastOccurrence[i] = patternSize; - - for(size_t i = 0; i < patternSize - 1; ++i) - lastOccurrence[static_cast(*(patternBegin + i))] = patternSize - i - 1; - - for(TIterator it = dataBegin + patternSize - 1 + offset; - it < dataEnd; - it += lastOccurrence[static_cast(*it)]) + while(*itBuffer == *itPattern) { - TIterator itBuffer = it; - TIterator itPattern = patternBegin + patternSize - 1; - - while(*itBuffer == *itPattern) + if(itPattern == patternBegin) { - if(itPattern == patternBegin) - { - if((itBuffer - dataBegin - offset) % byteAlign == 0) - return (itBuffer - dataBegin); - else - break; - } - - --itBuffer; - --itPattern; + if((itBuffer - dataBegin - offset) % byteAlign == 0) + return (itBuffer - dataBegin); + else + break; } - } - return ByteVector::npos; + --itBuffer; + --itPattern; + } } -#if defined(TAGLIB_MSC_BYTESWAP) || defined(TAGLIB_GCC_BYTESWAP) + return ByteVector::npos; +} - template - T byteSwap(T x) - { - // There should be all counterparts of to*() and from*() overloads for integral types. - debug("byteSwap() -- Non specialized version should not be called"); +template +T byteSwap(T x) +{ + // There should be all counterparts of to*() and from*() overloads for integral types. + debug("byteSwap() -- Non specialized version should not be called"); + return 0; +} + +template <> +ushort byteSwap(ushort x) +{ + return byteSwap16(x); +} + +template <> +uint byteSwap(uint x) +{ + return byteSwap32(x); +} + +template <> +ulonglong byteSwap(ulonglong x) +{ + return byteSwap64(x); +} + +template +T toNumber(const ByteVector &v, bool mostSignificantByteFirst) +{ + if(v.isEmpty()) { + debug("toNumber() -- data is empty, returning 0"); return 0; } -#endif - -#ifdef TAGLIB_MSC_BYTESWAP - - template <> - unsigned short byteSwap(unsigned short x) - { - return _byteswap_ushort(x); + if(v.size() >= sizeof(T)) { + if(isLittleEndianSystem == mostSignificantByteFirst) + return byteSwap(*reinterpret_cast(v.data())); + else + return *reinterpret_cast(v.data()); } - - template <> - unsigned int byteSwap(unsigned int x) - { - return _byteswap_ulong(x); - } - - template <> - unsigned long long byteSwap(unsigned long long x) - { - return _byteswap_uint64(x); - } - -#endif - -#ifdef TAGLIB_GCC_BYTESWAP - - template <> - unsigned short byteSwap(unsigned short x) - { - return __bswap_16(x); - } - - template <> - unsigned int byteSwap(unsigned int x) - { - return __bswap_32(x); - } - - template <> - unsigned long long byteSwap(unsigned long long x) - { - return __bswap_64(x); - } - -#endif - - template - T toNumber(const ByteVector &v, bool mostSignificantByteFirst) - { - if(v.isEmpty()) { - debug("toNumber() -- data is empty, returning 0"); - return 0; - } - - const size_t size = sizeof(T); - -#if defined(TAGLIB_MSC_BYTESWAP) || defined(TAGLIB_GCC_BYTESWAP) - - if(v.size() >= size) - { - if(mostSignificantByteFirst) - return byteSwap(*reinterpret_cast(v.data())); - else - return *reinterpret_cast(v.data()); - } - -#endif - - const size_t last = v.size() > size ? size - 1 : v.size() - 1; + else { T sum = 0; - for(size_t i = 0; i <= last; i++) - sum |= (T) uchar(v[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); + for(size_t i = 0; i < v.size(); i++) { + const size_t shift = (mostSignificantByteFirst ? v.size() - 1 - i : i) * 8; + sum |= static_cast(static_cast(v[i]) << shift); + } return sum; } - - template - ByteVector fromNumber(T value, bool mostSignificantByteFirst) - { - const size_t size = sizeof(T); - -#if defined(TAGLIB_MSC_BYTESWAP) || defined(TAGLIB_GCC_BYTESWAP) - - if(mostSignificantByteFirst) - value = byteSwap(value); - - return ByteVector(reinterpret_cast(&value), size); - -#else - - ByteVector v(size, 0); - for(size_t i = 0; i < size; i++) - v[i] = uchar(value >> ((mostSignificantByteFirst ? size - 1 - i : i) * 8) & 0xff); - - return v; - -#endif - } } -using namespace TagLib; +template +ByteVector fromNumber(T value, bool mostSignificantByteFirst) +{ + const size_t size = sizeof(T); + + if(isLittleEndianSystem == mostSignificantByteFirst) + value = byteSwap(value); + + return ByteVector(reinterpret_cast(&value), size); +} class DataPrivate : public RefCounter { @@ -456,17 +406,17 @@ ByteVector ByteVector::fromCString(const char *s, size_t length) ByteVector ByteVector::fromUInt16(size_t value, bool mostSignificantByteFirst) { - return fromNumber(static_cast(value), mostSignificantByteFirst); + return fromNumber(static_cast(value), mostSignificantByteFirst); } ByteVector ByteVector::fromUInt32(size_t value, bool mostSignificantByteFirst) { - return fromNumber(static_cast(value), mostSignificantByteFirst); + return fromNumber(static_cast(value), mostSignificantByteFirst); } ByteVector ByteVector::fromUInt64(ulonglong value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, mostSignificantByteFirst); } //////////////////////////////////////////////////////////////////////////////// @@ -993,9 +943,10 @@ void ByteVector::detach() // related functions //////////////////////////////////////////////////////////////////////////////// -std::ostream &TagLib::operator<<(std::ostream &s, const ByteVector &v) +std::ostream &operator<<(std::ostream &s, const ByteVector &v) { - for(TagLib::uint i = 0; i < v.size(); i++) + for(size_t i = 0; i < v.size(); i++) s << v[i]; return s; } +} diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 358d7975..d7d3b4c1 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -23,9 +23,13 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +// This class assumes that std::basic_string has a contiguous and null-terminated buffer. +// + #include "tstring.h" #include "tdebug.h" #include "tstringlist.h" +#include "tbyteswap.h" #include @@ -48,45 +52,10 @@ namespace { - inline unsigned short byteSwap(unsigned short x) - { -#if defined(_MSC_VER) && (_MSC_VER >= 1400) - - return _byteswap_ushort(x); - -#elif defined(__GNUC__) - - return __bswap_16(x); - -#else - - return (((x) >> 8) & 0xff) | (((x) & 0xff) << 8); - -#endif - } - inline unsigned short combine(unsigned char c1, unsigned char c2) { return (c1 << 8) | c2; } - -#if !defined(TAGLIB_LITTLE_ENDIAN) && !defined(TAGLIB_BIG_ENDIAN) - - String::Type wcharByteOrder() - { - // Detect CPU endian at run time. - union { - TagLib::ushort w; - char c; - } x = { 0x1234 }; - - if(x.c == 0x34) - return String::UTF16LE; - else - return String::UTF16BE; - } - -#endif } namespace TagLib { @@ -613,7 +582,6 @@ String String::number(int n) // static TagLib::wchar &String::operator[](size_t i) { detach(); - return d->data[i]; } @@ -971,7 +939,7 @@ void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) if(swap) { for(size_t i = 0; i < length; ++i) - d->data[i] = byteSwap(static_cast(s[i])); + d->data[i] = byteSwap16(static_cast(s[i])); } } @@ -1017,19 +985,7 @@ void String::copyFromUTF16(const char *s, size_t length, Type t) internalCopyFromUTF16(s, length, t); } -#if defined(TAGLIB_LITTLE_ENDIAN) - -const String::Type String::WCharByteOrder = String::UTF16LE; - -#elif defined(TAGLIB_BIG_ENDIAN) - -const String::Type String::WCharByteOrder = String::UTF16BE; - -#else - -const String::Type String::WCharByteOrder = wcharByteOrder(); - -#endif +const String::Type String::WCharByteOrder = isLittleEndianSystem ? String::UTF16LE : String::UTF16BE; //////////////////////////////////////////////////////////////////////////////// // related functions @@ -1037,26 +993,26 @@ const String::Type String::WCharByteOrder = wcharByteOrder(); const String operator+(const String &s1, const String &s2) { - String s(s1); + TagLib::String s(s1); s.append(s2); return s; } const String operator+(const char *s1, const String &s2) { - String s(s1); + TagLib::String s(s1); s.append(s2); return s; } const String operator+(const String &s1, const char *s2) { - String s(s1); + TagLib::String s(s1); s.append(s2); return s; } -std::ostream &operator<<(std::ostream &s, const String &str) +std::ostream &operator<<(std::ostream &s, const TagLib::String &str) { s << str.to8Bit(); return s; diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index 780b5e7b..e1665fd5 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -563,7 +563,6 @@ namespace TagLib { * Send the string to an output stream. */ TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::String &str); - } #endif diff --git a/tests/test_flacpicture.cpp b/tests/test_flacpicture.cpp index b61d0caf..e2d64f48 100644 --- a/tests/test_flacpicture.cpp +++ b/tests/test_flacpicture.cpp @@ -22,8 +22,10 @@ public: void testParse() { - char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; - FLAC::Picture pic(ByteVector(data, 199)); + const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; + const char *pdata = reinterpret_cast(data); + + FLAC::Picture pic(ByteVector(pdata, 199)); CPPUNIT_ASSERT_EQUAL(3, int(pic.type())); CPPUNIT_ASSERT_EQUAL(1, pic.width()); @@ -37,9 +39,11 @@ public: void testPassThrough() { - char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; - FLAC::Picture pic(ByteVector(data, 199)); - CPPUNIT_ASSERT_EQUAL(ByteVector(data, 199), pic.render()); + const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; + const char *pdata = reinterpret_cast(data); + + FLAC::Picture pic(ByteVector(pdata, 199)); + CPPUNIT_ASSERT_EQUAL(ByteVector(pdata, 199), pic.render()); } }; diff --git a/tests/test_string.cpp b/tests/test_string.cpp index de5efefd..2b7a9323 100644 --- a/tests/test_string.cpp +++ b/tests/test_string.cpp @@ -42,6 +42,7 @@ class TestString : public CppUnit::TestFixture CPPUNIT_TEST(testAppendStringDetach); CPPUNIT_TEST(testToInt); CPPUNIT_TEST(testSubstr); + CPPUNIT_TEST(testNewline); CPPUNIT_TEST_SUITE_END(); public: @@ -201,6 +202,22 @@ public: CPPUNIT_ASSERT_EQUAL(String("123456"), String("0123456").substr(1, 200)); } + void testNewline() + { + ByteVector cr("abc\x0dxyz", 7); + ByteVector lf("abc\x0axyz", 7); + ByteVector crlf("abc\x0d\x0axyz", 8); + + CPPUNIT_ASSERT_EQUAL(size_t(7), String(cr).size()); + CPPUNIT_ASSERT_EQUAL(size_t(7), String(lf).size()); + CPPUNIT_ASSERT_EQUAL(size_t(8), String(crlf).size()); + + CPPUNIT_ASSERT_EQUAL(L'\x0d', String(cr)[3]); + CPPUNIT_ASSERT_EQUAL(L'\x0a', String(lf)[3]); + CPPUNIT_ASSERT_EQUAL(L'\x0d', String(crlf)[3]); + CPPUNIT_ASSERT_EQUAL(L'\x0a', String(crlf)[4]); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestString);