diff --git a/examples/framelist.cpp b/examples/framelist.cpp index dbe80feb..679aa393 100644 --- a/examples/framelist.cpp +++ b/examples/framelist.cpp @@ -95,7 +95,10 @@ int main(int argc, char *argv[]) for(APE::ItemListMap::ConstIterator it = ape->itemListMap().begin(); it != ape->itemListMap().end(); ++it) { - cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl; + if((*it).second.type() != APE::Item::Binary) + cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl; + else + cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << endl; } } else diff --git a/taglib/ape/apeitem.cpp b/taglib/ape/apeitem.cpp index 779a94d6..db729cdf 100644 --- a/taglib/ape/apeitem.cpp +++ b/taglib/ape/apeitem.cpp @@ -125,35 +125,40 @@ void APE::Item::setBinaryData(const ByteVector &value) { d->type = Binary; d->value = value; + d->text.clear(); } void APE::Item::setKey(const String &key) { - d->key = key; + d->key = key; } void APE::Item::setValue(const String &value) { - d->type = Text; - d->text = value; + d->type = Text; + d->text = value; + d->value.clear(); } void APE::Item::setValues(const StringList &value) { - d->type = Text; - d->text = value; + d->type = Text; + d->text = value; + d->value.clear(); } void APE::Item::appendValue(const String &value) { - d->type = Text; - d->text.append(value); + d->type = Text; + d->text.append(value); + d->value.clear(); } void APE::Item::appendValues(const StringList &values) { - d->type = Text; - d->text.append(values); + d->type = Text; + d->text.append(values); + d->value.clear(); } int APE::Item::size() const @@ -187,7 +192,10 @@ StringList APE::Item::values() const String APE::Item::toString() const { - return isEmpty() ? String::null : d->text.front(); + if(d->type == Text && !isEmpty()) + return d->text.front(); + else + return String::null; } bool APE::Item::isEmpty() const @@ -221,13 +229,15 @@ void APE::Item::parse(const ByteVector &data) d->key = String(data.mid(8), String::UTF8); - d->value = data.mid(8 + d->key.size() + 1, valueLength); + const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength); setReadOnly(flags & 1); setType(ItemTypes((flags >> 1) & 3)); - if(Text == d->type) - d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8); + if(Text == d->type) + d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8); + else + d->value = value; } ByteVector APE::Item::render() const diff --git a/taglib/ape/apeitem.h b/taglib/ape/apeitem.h index eb460d23..d2286153 100644 --- a/taglib/ape/apeitem.h +++ b/taglib/ape/apeitem.h @@ -96,7 +96,7 @@ namespace TagLib { /*! * Returns the binary value. - * If the item type is not \a Binary, the returned contents are undefined + * If the item type is not \a Binary, always returns an empty ByteVector. */ ByteVector binaryData() const; @@ -146,13 +146,15 @@ namespace TagLib { int size() const; /*! - * Returns the value as a single string. In case of multiple strings, - * the first is returned. + * Returns the value as a single string. In case of multiple strings, + * the first is returned. If the data type is not \a Text, always returns + * an empty String. */ String toString() const; /*! - * Returns the list of text values. + * Returns the list of text values. If the data type is not \a Text, always + * returns an empty StringList. */ StringList values() const; diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index bb3d43dc..889afaea 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -158,9 +158,8 @@ size_t findVector( 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)]) + TIterator it = dataBegin + patternSize - 1 + offset; + while(true) { TIterator itBuffer = it; TIterator itPattern = patternBegin + patternSize - 1; @@ -178,27 +177,21 @@ size_t findVector( --itBuffer; --itPattern; } + + const size_t step = lastOccurrence[static_cast(*it)]; + if(dataEnd - step <= it) + break; + + it += step; } return ByteVector::npos; } - -namespace { - enum Endianness { - LittleEndian, - BigEndian - }; -} - -template +template inline T toNumber(const ByteVector &v, size_t offset) { -#if SYSTEM_BYTEORDER == 1 - static const bool swap = (ENDIAN == BigEndian); -#else - static const bool swap = (ENDIAN == LittleEndian); -#endif + static const bool swap = (ENDIAN != Utils::SystemByteOrder); if(LENGTH >= sizeof(T) && offset + LENGTH <= v.size()) { @@ -207,7 +200,7 @@ inline T toNumber(const ByteVector &v, size_t offset) ::memcpy(&tmp, v.data() + offset, sizeof(T)); if(swap) - return byteSwap(tmp); + return Utils::byteSwap(tmp); else return tmp; } @@ -216,7 +209,7 @@ inline T toNumber(const ByteVector &v, size_t offset) const size_t length = std::min(LENGTH, v.size() - offset); T sum = 0; for(size_t i = 0; i < length; i++) { - const size_t shift = (ENDIAN == LittleEndian ? i : length - 1 - i) * 8; + const size_t shift = (swap ? length - 1 - i : i) * 8; sum |= static_cast(static_cast(v[offset + i])) << shift; } @@ -229,17 +222,13 @@ inline T toNumber(const ByteVector &v, size_t offset) } } -template +template inline ByteVector fromNumber(T value) { -#if SYSTEM_BYTEORDER == 1 - static const bool swap = (ENDIAN == BigEndian); -#else - static const bool swap = (ENDIAN == LittleEndian); -#endif + static const bool swap = (ENDIAN != Utils::SystemByteOrder); if(swap) - value = byteSwap(value); + value = Utils::byteSwap(value); return ByteVector(reinterpret_cast(&value), sizeof(T)); } @@ -310,32 +299,32 @@ ByteVector ByteVector::fromCString(const char *s, size_t length) ByteVector ByteVector::fromUInt16LE(size_t value) { - return fromNumber(static_cast(value)); + return fromNumber(static_cast(value)); } ByteVector ByteVector::fromUInt16BE(size_t value) { - return fromNumber(static_cast(value)); + return fromNumber(static_cast(value)); } ByteVector ByteVector::fromUInt32LE(size_t value) { - return fromNumber(static_cast(value)); + return fromNumber(static_cast(value)); } ByteVector ByteVector::fromUInt32BE(size_t value) { - return fromNumber(static_cast(value)); + return fromNumber(static_cast(value)); } ByteVector ByteVector::fromUInt64LE(ulonglong value) { - return fromNumber(value); + return fromNumber(value); } ByteVector ByteVector::fromUInt64BE(ulonglong value) { - return fromNumber(value); + return fromNumber(value); } //////////////////////////////////////////////////////////////////////////////// @@ -658,52 +647,52 @@ TagLib::uint ByteVector::checksum() const short ByteVector::toInt16LE(size_t offset) const { - return static_cast(toNumber(*this, offset)); + return static_cast(toNumber(*this, offset)); } short ByteVector::toInt16BE(size_t offset) const { - return static_cast(toNumber(*this, offset)); + return static_cast(toNumber(*this, offset)); } ushort ByteVector::toUInt16LE(size_t offset) const { - return toNumber(*this, offset); + return toNumber(*this, offset); } ushort ByteVector::toUInt16BE(size_t offset) const { - return toNumber(*this, offset); + return toNumber(*this, offset); } uint ByteVector::toUInt24LE(size_t offset) const { - return toNumber(*this, offset); + return toNumber(*this, offset); } uint ByteVector::toUInt24BE(size_t offset) const { - return toNumber(*this, offset); + return toNumber(*this, offset); } uint ByteVector::toUInt32LE(size_t offset) const { - return toNumber(*this, offset); + return toNumber(*this, offset); } uint ByteVector::toUInt32BE(size_t offset) const { - return toNumber(*this, offset); + return toNumber(*this, offset); } long long ByteVector::toInt64LE(size_t offset) const { - return static_cast(toNumber(*this, offset)); + return static_cast(toNumber(*this, offset)); } long long ByteVector::toInt64BE(size_t offset) const { - return static_cast(toNumber(*this, offset)); + return static_cast(toNumber(*this, offset)); } float ByteVector::toFloat32BE(size_t offset) const @@ -725,9 +714,8 @@ float ByteVector::toFloat32BE(size_t offset) const } tmp; ::memcpy(&tmp, data() + offset, 4); -# if SYSTEM_BYTEORDER == 1 - tmp.i = byteSwap(tmp.i); -# endif + if(Utils::SystemByteOrder == Utils::LittleEndian) + tmp.i = Utils::byteSwap(tmp.i); return tmp.f; } @@ -786,9 +774,8 @@ double ByteVector::toFloat64BE(size_t offset) const } tmp; ::memcpy(&tmp, data() + offset, 8); -# if SYSTEM_BYTEORDER == 1 - tmp.i = byteSwap(tmp.i); -# endif + if(Utils::SystemByteOrder == Utils::LittleEndian) + tmp.i = Utils::byteSwap(tmp.i); return tmp.f; } diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index ad0f7e7b..2887c09f 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -782,7 +782,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] = Utils::byteSwap(static_cast(s[i])); } } @@ -821,15 +821,8 @@ void String::copyFromUTF16(const char *s, size_t length, Type t) } } -#if SYSTEM_BYTEORDER == 1 - -const String::Type String::WCharByteOrder = String::UTF16LE; - -#else - -const String::Type String::WCharByteOrder = String::UTF16BE; - -#endif +const String::Type String::WCharByteOrder + = (Utils::SystemByteOrder == Utils::BigEndian) ? String::UTF16BE : String::UTF16LE; //////////////////////////////////////////////////////////////////////////////// // related functions diff --git a/taglib/toolkit/tutils.h b/taglib/toolkit/tutils.h index 73c35716..4a398d26 100644 --- a/taglib/toolkit/tutils.h +++ b/taglib/toolkit/tutils.h @@ -46,105 +46,144 @@ namespace TagLib { - - inline ushort byteSwap(ushort x) + namespace Utils { + inline ushort byteSwap(ushort x) + { #if defined(HAVE_GCC_BYTESWAP_16) - return __builtin_bswap16(x); + return __builtin_bswap16(x); #elif defined(HAVE_MSC_BYTESWAP) - return _byteswap_ushort(x); + return _byteswap_ushort(x); #elif defined(HAVE_GLIBC_BYTESWAP) - return __bswap_16(x); + return __bswap_16(x); #elif defined(HAVE_MAC_BYTESWAP) - return OSSwapInt16(x); + return OSSwapInt16(x); #elif defined(HAVE_OPENBSD_BYTESWAP) - return swap16(x); + return swap16(x); #else - return ((x >> 8) & 0xff) | ((x & 0xff) << 8); + return ((x >> 8) & 0xff) | ((x & 0xff) << 8); #endif - } + } - inline uint byteSwap(uint x) - { + inline uint byteSwap(uint x) + { #if defined(HAVE_GCC_BYTESWAP_32) - return __builtin_bswap32(x); + return __builtin_bswap32(x); #elif defined(HAVE_MSC_BYTESWAP) - return _byteswap_ulong(x); + return _byteswap_ulong(x); #elif defined(HAVE_GLIBC_BYTESWAP) - return __bswap_32(x); + return __bswap_32(x); #elif defined(HAVE_MAC_BYTESWAP) - return OSSwapInt32(x); + return OSSwapInt32(x); #elif defined(HAVE_OPENBSD_BYTESWAP) - return swap32(x); + return swap32(x); #else - return ((x & 0xff000000u) >> 24) - | ((x & 0x00ff0000u) >> 8) - | ((x & 0x0000ff00u) << 8) - | ((x & 0x000000ffu) << 24); + return ((x & 0xff000000u) >> 24) + | ((x & 0x00ff0000u) >> 8) + | ((x & 0x0000ff00u) << 8) + | ((x & 0x000000ffu) << 24); #endif - } + } - inline ulonglong byteSwap(ulonglong x) - { + inline ulonglong byteSwap(ulonglong x) + { #if defined(HAVE_GCC_BYTESWAP_64) - return __builtin_bswap64(x); + return __builtin_bswap64(x); #elif defined(HAVE_MSC_BYTESWAP) - return _byteswap_uint64(x); + return _byteswap_uint64(x); #elif defined(HAVE_GLIBC_BYTESWAP) - return __bswap_64(x); + return __bswap_64(x); #elif defined(HAVE_MAC_BYTESWAP) - return OSSwapInt64(x); + return OSSwapInt64(x); #elif defined(HAVE_OPENBSD_BYTESWAP) - return swap64(x); + return swap64(x); #else - return ((x & 0xff00000000000000ull) >> 56) - | ((x & 0x00ff000000000000ull) >> 40) - | ((x & 0x0000ff0000000000ull) >> 24) - | ((x & 0x000000ff00000000ull) >> 8) - | ((x & 0x00000000ff000000ull) << 8) - | ((x & 0x0000000000ff0000ull) << 24) - | ((x & 0x000000000000ff00ull) << 40) - | ((x & 0x00000000000000ffull) << 56); + return ((x & 0xff00000000000000ull) >> 56) + | ((x & 0x00ff000000000000ull) >> 40) + | ((x & 0x0000ff0000000000ull) >> 24) + | ((x & 0x000000ff00000000ull) >> 8) + | ((x & 0x00000000ff000000ull) << 8) + | ((x & 0x0000000000ff0000ull) << 24) + | ((x & 0x000000000000ff00ull) << 40) + | ((x & 0x00000000000000ffull) << 56); + +#endif + } + + enum ByteOrder + { + LittleEndian, + BigEndian + }; + +#ifdef SYSTEM_BYTEORDER + +# if SYSTEM_BYTEORDER == 1 + + const ByteOrder SystemByteOrder = LittleEndian; + +# else + + const ByteOrder SystemByteOrder = BigEndian; + +# endif + +#else + + inline ByteOrder systemByteOrder() + { + union { + int i; + char c; + } u; + + u.i = 1; + if(u.c == 1) + return LittleEndian; + else + return BigEndian; + } + + const ByteOrder SystemByteOrder = systemByteOrder(); #endif } - -}; +} #endif diff --git a/tests/test_apetag.cpp b/tests/test_apetag.cpp index 5d2df9b6..c7516994 100644 --- a/tests/test_apetag.cpp +++ b/tests/test_apetag.cpp @@ -20,6 +20,7 @@ class TestAPETag : public CppUnit::TestFixture CPPUNIT_TEST(testPropertyInterface1); CPPUNIT_TEST(testPropertyInterface2); CPPUNIT_TEST(testInvalidKeys); + CPPUNIT_TEST(testTextBinary); CPPUNIT_TEST_SUITE_END(); public: @@ -97,6 +98,23 @@ public: CPPUNIT_ASSERT(unsuccessful.contains("A")); CPPUNIT_ASSERT(unsuccessful.contains("MP+")); } + + void testTextBinary() + { + APE::Item item = APE::Item("DUMMY", "Test Text"); + CPPUNIT_ASSERT_EQUAL(String("Test Text"), item.toString()); + CPPUNIT_ASSERT_EQUAL(ByteVector::null, item.binaryData()); + + ByteVector data("Test Data"); + item.setBinaryData(data); + CPPUNIT_ASSERT(item.values().isEmpty()); + CPPUNIT_ASSERT_EQUAL(String::null, item.toString()); + CPPUNIT_ASSERT_EQUAL(data, item.binaryData()); + + item.setValue("Test Text 2"); + CPPUNIT_ASSERT_EQUAL(String("Test Text 2"), item.toString()); + CPPUNIT_ASSERT_EQUAL(ByteVector::null, item.binaryData()); + } };