From d52e97dfcd1c4c7385c1ca9c334e9571da330162 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Tue, 1 Jan 2013 04:28:00 -0500 Subject: [PATCH 01/15] c: Add support for TAGLIB_STATIC to the C bindings Otherwise, we'll fail with dllimport/dllexport linking errors on Windows. --- bindings/c/tag_c.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 80af92a715f0981b21051e4b10a164d415e3232c Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Thu, 3 Jan 2013 23:00:17 +0100 Subject: [PATCH 02/15] Add forwarders for the property interface to Ogg::FLAC::File. Fixes an infinite method resolution recursion in File::properties() and File::setProperties(). Thanks to Sebastian Rachuj for pointing out this bug. --- taglib/ogg/flac/oggflacfile.cpp | 11 +++++++++++ taglib/ogg/flac/oggflacfile.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index b73c5f57..510c01f8 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 8558cfdf..770884a7 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. From 08863dec0bb3ae324e53041378de6ef707ae584b Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Thu, 3 Jan 2013 23:20:15 +0100 Subject: [PATCH 03/15] Found and fixed more missing property interface forwarders. Probably due to a copy-and-paste error the implementation of File::removeUnsupportedProperties() contained cases for several type which do not reimplement this method; for others the implementation was missing and is now included. In addition, the formats Speex and Opus suffered from the same bug as OggFLAC in the commit before, which is now fixed. --- taglib/ogg/opus/opusfile.cpp | 11 +++++++++++ taglib/ogg/opus/opusfile.h | 12 ++++++++++++ taglib/ogg/speex/speexfile.cpp | 11 +++++++++++ taglib/ogg/speex/speexfile.h | 14 ++++++++++++++ taglib/riff/aiff/aifffile.cpp | 5 +++++ taglib/riff/aiff/aifffile.h | 2 ++ taglib/riff/wav/wavfile.cpp | 9 +++++++-- taglib/riff/wav/wavfile.h | 2 ++ taglib/toolkit/tfile.cpp | 10 ---------- taglib/trueaudio/trueaudiofile.cpp | 6 ++++++ taglib/trueaudio/trueaudiofile.h | 2 ++ taglib/wavpack/wavpackfile.cpp | 8 ++++++++ taglib/wavpack/wavpackfile.h | 2 ++ 13 files changed, 82 insertions(+), 12 deletions(-) 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/tfile.cpp b/taglib/toolkit/tfile.cpp index 7251f3f7..fdb5237f 100644 --- a/taglib/toolkit/tfile.cpp +++ b/taglib/toolkit/tfile.cpp @@ -172,26 +172,16 @@ void File::removeUnsupportedProperties(const StringList &properties) dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast(this)) - dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) diff --git a/taglib/trueaudio/trueaudiofile.cpp b/taglib/trueaudio/trueaudiofile.cpp index 85e5a21b..9bac29f0 100644 --- a/taglib/trueaudio/trueaudiofile.cpp +++ b/taglib/trueaudio/trueaudiofile.cpp @@ -139,6 +139,12 @@ PropertyMap TrueAudio::File::properties() const return PropertyMap(); } +void TrueAudio::File::removeUnsupportedProperties(const StringList &unsupported) +{ + if(d->hasID3v2) + d->tag.access(TrueAudioID3v2Index, false)->removeUnsupportedProperties(unsupported); +} + PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) diff --git a/taglib/trueaudio/trueaudiofile.h b/taglib/trueaudio/trueaudiofile.h index 1b8a9353..be31089e 100644 --- a/taglib/trueaudio/trueaudiofile.h +++ b/taglib/trueaudio/trueaudiofile.h @@ -144,6 +144,8 @@ namespace TagLib { */ PropertyMap setProperties(const PropertyMap &); + void removeUnsupportedProperties(const StringList &properties); + /*! * Returns the TrueAudio::Properties for this file. If no audio properties * were read then this will return a null pointer. diff --git a/taglib/wavpack/wavpackfile.cpp b/taglib/wavpack/wavpackfile.cpp index 78df182d..3754ea86 100644 --- a/taglib/wavpack/wavpackfile.cpp +++ b/taglib/wavpack/wavpackfile.cpp @@ -117,6 +117,14 @@ PropertyMap WavPack::File::properties() const return PropertyMap(); } + +void WavPack::File::removeUnsupportedProperties(const StringList &unsupported) +{ + if(d->hasAPE) + d->tag.access(WavAPEIndex, false)->removeUnsupportedProperties(unsupported); +} + + PropertyMap WavPack::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) diff --git a/taglib/wavpack/wavpackfile.h b/taglib/wavpack/wavpackfile.h index 918edca8..7d4fafee 100644 --- a/taglib/wavpack/wavpackfile.h +++ b/taglib/wavpack/wavpackfile.h @@ -116,6 +116,8 @@ namespace TagLib { */ PropertyMap properties() const; + void removeUnsupportedProperties(const StringList &properties); + /*! * Implements the unified property interface -- import function. * Creates an APE tag if it does not exists and calls setProperties() on From 077208d17afe91014364a1fb923951f8357c33ae Mon Sep 17 00:00:00 2001 From: rsjtdrjgfuzkfg Date: Fri, 18 Jan 2013 17:21:35 +0100 Subject: [PATCH 04/15] Create UTF8-Lyrics per default. --- taglib/mpeg/id3v2/id3v2frame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index 1079785d..4fad5f1e 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -129,7 +129,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; From e9fec47411ffac3d94e8c357f6b9e85036c2dc11 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 19 Mar 2013 21:51:52 +0900 Subject: [PATCH 05/15] Fix warnings in test_flacpicture.cpp --- tests/test_flacpicture.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/test_flacpicture.cpp b/tests/test_flacpicture.cpp index 0ba9452f..eefa9306 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()); } }; From 703736fbcb0582ee433f4a23f038f9e9ba6a6233 Mon Sep 17 00:00:00 2001 From: Urs Fleisch Date: Sat, 23 Mar 2013 13:56:31 +0100 Subject: [PATCH 06/15] Parameter to disable duplication between ID3v1 and ID3v2 tags, #115. --- taglib/mpeg/mpegfile.cpp | 22 ++++++++++++++++------ taglib/mpeg/mpegfile.h | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index c73da414..51cb5784 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -186,6 +186,11 @@ bool MPEG::File::save(int tags, bool stripOthers) } 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); @@ -203,14 +208,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; diff --git a/taglib/mpeg/mpegfile.h b/taglib/mpeg/mpegfile.h index 1d99898c..0c817887 100644 --- a/taglib/mpeg/mpegfile.h +++ b/taglib/mpeg/mpegfile.h @@ -213,6 +213,24 @@ namespace TagLib { // BIC: combine with the above method bool save(int tags, bool stripOthers, int id3v2Version); + /*! + * 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. * From a4e68a030475a6096ddca83805fef848c2863d87 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Fri, 5 Apr 2013 22:07:58 +0900 Subject: [PATCH 07/15] Reduce unnecessary memory copies by ByteVector --- taglib/toolkit/tbytevector.cpp | 572 +++++++++++++++++++++------------ taglib/toolkit/tbytevector.h | 36 ++- 2 files changed, 399 insertions(+), 209 deletions(-) diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 59e3a9ed..89785d04 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -30,6 +30,16 @@ #include +#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(_M_IX86) || defined(_M_X64)) +# define TAGLIB_MSC_BYTESWAP +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# define TAGLIB_GCC_BYTESWAP +#endif + +#ifdef TAGLIB_GCC_BYTESWAP +# include +#endif + #include "tbytevector.h" // This is a bit ugly to keep writing over and over again. @@ -39,7 +49,7 @@ // // http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp -#define DATA(x) (&(x->data[0])) +#define DATA(x) (&(x->data->data[0])) namespace TagLib { static const char hexTable[17] = "0123456789abcdef"; @@ -91,130 +101,171 @@ namespace TagLib { }; /*! - * A templatized KMP find that works both with a ByteVector and a ByteVectorMirror. + * A templatized straightforward find that works with the types + * std::vector::iterator and std::vector::reverse_iterator. */ - - template - int vectorFind(const Vector &v, const Vector &pattern, uint offset, int byteAlign) + template + int findChar( + const TIterator dataBegin, const TIterator dataEnd, + char c, uint offset, int byteAlign) { - if(pattern.size() > v.size() || offset > v.size() - 1) + const size_t dataSize = dataEnd - dataBegin; + if(dataSize == 0 || offset > dataSize - 1) return -1; - // Let's go ahead and special case a pattern of size one since that's common - // and easy to make fast. + // n % 0 is invalid - if(pattern.size() == 1) { - char p = pattern[0]; - for(uint i = offset; i < v.size(); i++) { - if(v[i] == p && (i - offset) % byteAlign == 0) - return i; - } + if(byteAlign == 0) return -1; - } - uchar lastOccurrence[256]; - - for(uint i = 0; i < 256; ++i) - lastOccurrence[i] = uchar(pattern.size()); - - for(uint i = 0; i < pattern.size() - 1; ++i) - lastOccurrence[uchar(pattern[i])] = uchar(pattern.size() - i - 1); - - for(uint i = pattern.size() - 1 + offset; i < v.size(); i += lastOccurrence[uchar(v.at(i))]) { - int iBuffer = i; - int iPattern = pattern.size() - 1; - - while(iPattern >= 0 && v.at(iBuffer) == pattern[iPattern]) { - --iBuffer; - --iPattern; - } - - if(-1 == iPattern && (iBuffer + 1 - offset) % byteAlign == 0) - return iBuffer + 1; + for(TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { + if(*it == c) + return (it - dataBegin); } return -1; } /*! - * Wraps the accessors to a ByteVector to make the search algorithm access the - * elements in reverse. - * - * \see vectorFind() - * \see ByteVector::rfind() + * A templatized KMP find that works with the types + * std::vector::iterator and std::vector::reverse_iterator. */ - - class ByteVectorMirror + template + int findVector( + const TIterator dataBegin, const TIterator dataEnd, + const TIterator patternBegin, const TIterator patternEnd, + uint offset, int byteAlign) { - public: - ByteVectorMirror(const ByteVector &source) : v(source) {} + const size_t dataSize = dataEnd - dataBegin; + const size_t patternSize = patternEnd - patternBegin; + if(patternSize > dataSize || offset > dataSize - 1) + return -1; - char operator[](int index) const + // n % 0 is invalid + + if(byteAlign == 0) + return -1; + + // Special case that 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)]) { - return v[v.size() - index - 1]; - } + TIterator itBuffer = it; + TIterator itPattern = patternBegin + patternSize - 1; - char at(int index) const - { - return v.at(v.size() - index - 1); - } + while(*itBuffer == *itPattern) + { + if(itPattern == patternBegin) + { + if((itBuffer - dataBegin - offset) % byteAlign == 0) + return (itBuffer - dataBegin); + else + break; + } - ByteVectorMirror mid(uint index, uint length = 0xffffffff) const - { - return length == 0xffffffff ? v.mid(0, index) : v.mid(index - length, length); - } - - uint size() const - { - return v.size(); - } - - int find(const ByteVectorMirror &pattern, uint offset = 0, int byteAlign = 1) const - { - ByteVectorMirror v(*this); - - if(offset > 0) { - offset = size() - offset - pattern.size(); - if(offset >= size()) - offset = 0; + --itBuffer; + --itPattern; } - - const int pos = vectorFind(v, pattern, offset, byteAlign); - - // If the offset is zero then we need to adjust the location in the search - // to be appropriately reversed. If not we need to account for the fact - // that the recursive call (called from the above line) has already ajusted - // for this but that the normal templatized find above will add the offset - // to the returned value. - // - // This is a little confusing at first if you don't first stop to think - // through the logic involved in the forward search. - - if(pos == -1) - return -1; - - return size() - pos - pattern.size(); } - private: - const ByteVector &v; - }; + return -1; + } + +#if defined(TAGLIB_MSC_BYTESWAP) || defined(TAGLIB_GCC_BYTESWAP) template - T toNumber(const std::vector &data, bool mostSignificantByteFirst) + T byteSwap(T x) { - T sum = 0; + // There should be all counterparts of to*() and from*() overloads for integral types. + debug("byteSwap() -- Non specialized version should not be called"); + return 0; + } - if(data.size() <= 0) { - debug("ByteVectorMirror::toNumber() -- data is empty, returning 0"); - return sum; +#endif + +#ifdef TAGLIB_MSC_BYTESWAP + + template <> + unsigned short byteSwap(unsigned short x) + { + return _byteswap_ushort(x); + } + + 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; } - uint size = sizeof(T); - uint last = data.size() > size ? size - 1 : data.size() - 1; + 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 uint last = v.size() > size ? size - 1 : v.size() - 1; + T sum = 0; for(uint i = 0; i <= last; i++) - sum |= (T) uchar(data[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); + sum |= (T) uchar(v[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); return sum; } @@ -222,31 +273,127 @@ namespace TagLib { template ByteVector fromNumber(T value, bool mostSignificantByteFirst) { - int size = sizeof(T); + 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(int i = 0; i < size; i++) + for(uint i = 0; i < size; i++) v[i] = uchar(value >> ((mostSignificantByteFirst ? size - 1 - i : i) * 8) & 0xff); return v; + +#endif } } using namespace TagLib; +class DataPrivate : public RefCounter +{ +public: + DataPrivate() + { + } + + DataPrivate(const std::vector &v, uint offset, uint length) + : data(v.begin() + offset, v.begin() + offset + length) + { + } + + DataPrivate(uint len, char c) + : data(len, c) + { + } + + std::vector data; +}; + class ByteVector::ByteVectorPrivate : public RefCounter { public: - ByteVectorPrivate() : RefCounter(), size(0) {} - ByteVectorPrivate(const std::vector &v) : RefCounter(), data(v), size(v.size()) {} - ByteVectorPrivate(TagLib::uint len, char value) : RefCounter(), data(len, value), size(len) {} + ByteVectorPrivate() + : RefCounter() + , data(new DataPrivate()) + , offset(0) + , length(0) + { + } - std::vector data; + ByteVectorPrivate(ByteVectorPrivate *d, uint o, uint l) + : RefCounter() + , data(d->data) + , offset(d->offset + o) + , length(l) + { + data->ref(); + } - // std::vector::size() is very slow, so we'll cache the value + ByteVectorPrivate(const std::vector &v, uint o, uint l) + : RefCounter() + , data(new DataPrivate(v, o, l)) + , offset(0) + , length(l) + { + } - uint size; + ByteVectorPrivate(uint l, char c) + : RefCounter() + , data(new DataPrivate(l, c)) + , offset(0) + , length(l) + { + } + + ByteVectorPrivate(const char *s, uint l) + : RefCounter() + , data(new DataPrivate()) + , offset(0) + , length(l) + { + data->data.resize(length); + memcpy(DATA(this), s, l); + } + + void detach() + { + if(data->count() > 1) { + data->deref(); + data = new DataPrivate(data->data, offset, length); + offset = 0; + } + } + + ~ByteVectorPrivate() + { + if(data->deref()) + delete data; + } + + ByteVectorPrivate &operator=(const ByteVectorPrivate &x) + { + if(&x != this) + { + if(data->deref()) + delete data; + + data = x.data; + data->ref(); + } + + return *this; + } + + DataPrivate *data; + uint offset; + uint length; }; //////////////////////////////////////////////////////////////////////////////// @@ -257,14 +404,10 @@ ByteVector ByteVector::null; ByteVector ByteVector::fromCString(const char *s, uint length) { - ByteVector v; - if(length == 0xffffffff) - v.setData(s); + return ByteVector(s, ::strlen(s)); else - v.setData(s, length); - - return v; + return ByteVector(s, length); } ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) @@ -274,12 +417,12 @@ ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, mostSignificantByteFirst); } ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, mostSignificantByteFirst); } //////////////////////////////////////////////////////////////////////////////// @@ -287,37 +430,40 @@ ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFir //////////////////////////////////////////////////////////////////////////////// ByteVector::ByteVector() + : d(new ByteVectorPrivate()) { - d = new ByteVectorPrivate; } ByteVector::ByteVector(uint size, char value) + : d(new ByteVectorPrivate(size, value)) { - d = new ByteVectorPrivate(size, value); } -ByteVector::ByteVector(const ByteVector &v) : d(v.d) +ByteVector::ByteVector(const ByteVector &v) + : d(v.d) +{ + d->ref(); +} + +ByteVector::ByteVector(const ByteVector &v, uint offset, uint length) + : d(new ByteVectorPrivate(v.d, offset, length)) { d->ref(); } ByteVector::ByteVector(char c) + : d(new ByteVectorPrivate(1, c)) { - d = new ByteVectorPrivate; - d->data.push_back(c); - d->size = 1; } ByteVector::ByteVector(const char *data, uint length) + : d(new ByteVectorPrivate(data, length)) { - d = new ByteVectorPrivate; - setData(data, length); } ByteVector::ByteVector(const char *data) + : d(new ByteVectorPrivate(data, ::strlen(data))) { - d = new ByteVectorPrivate; - setData(data); } ByteVector::~ByteVector() @@ -326,74 +472,71 @@ ByteVector::~ByteVector() delete d; } -ByteVector &ByteVector::setData(const char *data, uint length) +ByteVector &ByteVector::setData(const char *s, uint length) { - detach(); - - resize(length); - - if(length > 0) - ::memcpy(DATA(d), data, length); - + *this = ByteVector(s, length); return *this; } ByteVector &ByteVector::setData(const char *data) { - return setData(data, ::strlen(data)); + *this = ByteVector(data); + return *this; } char *ByteVector::data() { detach(); - return size() > 0 ? DATA(d) : 0; + return size() > 0 ? (DATA(d) + d->offset) : 0; } const char *ByteVector::data() const { - return size() > 0 ? DATA(d) : 0; + return size() > 0 ? (DATA(d) + d->offset) : 0; } ByteVector ByteVector::mid(uint index, uint length) const { - ByteVector v; - if(index > size()) - return v; + index = size(); - ConstIterator endIt; + if(length > size() - index) + length = size() - index; - if(length < size() - index) - endIt = d->data.begin() + index + length; - else - endIt = d->data.end(); - - v.d->data.insert(v.d->data.begin(), ConstIterator(d->data.begin() + index), endIt); - v.d->size = v.d->data.size(); - - return v; + return ByteVector(*this, index, length); } char ByteVector::at(uint index) const { - return index < size() ? d->data[index] : 0; + return index < size() ? DATA(d)[d->offset + index] : 0; } int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const { - return vectorFind(*this, pattern, offset, byteAlign); + return findVector( + begin(), end(), pattern.begin(), pattern.end(), offset, byteAlign); +} + +int ByteVector::find(char c, uint offset, int byteAlign) const +{ + return findChar(begin(), end(), c, offset, byteAlign); } int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const { - // Ok, this is a little goofy, but pretty cool after it sinks in. Instead of - // reversing the find method's Boyer-Moore search algorithm I created a "mirror" - // for a ByteVector to reverse the behavior of the accessors. + if(offset > 0) { + offset = size() - offset - pattern.size(); + if(offset >= size()) + offset = 0; + } - ByteVectorMirror v(*this); - ByteVectorMirror p(pattern); + const int pos = findVector( + rbegin(), rend(), pattern.rbegin(), pattern.rend(), offset, byteAlign); - return v.find(p, offset, byteAlign); + if(pos == -1) + return -1; + else + return size() - pos - pattern.size(); } bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint patternOffset, uint patternLength) const @@ -403,17 +546,10 @@ bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint pattern // do some sanity checking -- all of these things are needed for the search to be valid - if(patternLength > size() || offset >= size() || patternOffset >= pattern.size() || patternLength == 0) + if(offset + patternLength > size() || patternOffset >= pattern.size() || patternLength == 0) return false; - - // loop through looking for a mismatch - - for(uint i = 0; i < patternLength - patternOffset; i++) { - if(at(i + offset) != pattern[i + patternOffset]) - return false; - } - - return true; + + return (::memcmp(data() + offset, pattern.data() + patternOffset, patternLength - patternOffset) == 0); } bool ByteVector::startsWith(const ByteVector &pattern) const @@ -511,74 +647,90 @@ int ByteVector::endsWithPartialMatch(const ByteVector &pattern) const ByteVector &ByteVector::append(const ByteVector &v) { - if(v.d->size == 0) - return *this; // Simply return if appending nothing. + if(v.d->length != 0) + { + detach(); - detach(); - - uint originalSize = d->size; - resize(d->size + v.d->size); - ::memcpy(DATA(d) + originalSize, DATA(v.d), v.size()); + uint originalSize = size(); + resize(originalSize + v.size()); + ::memcpy(data() + originalSize, v.data(), v.size()); + } return *this; } ByteVector &ByteVector::clear() { - detach(); - d->data.clear(); - d->size = 0; - + *this = ByteVector(); return *this; } TagLib::uint ByteVector::size() const { - return d->size; + return d->length; } ByteVector &ByteVector::resize(uint size, char padding) { - if(d->size < size) { - d->data.reserve(size); - d->data.insert(d->data.end(), size - d->size, padding); - } - else - d->data.erase(d->data.begin() + size, d->data.end()); - - d->size = size; + detach(); + d->data->data.resize(d->offset + size, padding); + d->length = size; return *this; } ByteVector::Iterator ByteVector::begin() { - return d->data.begin(); + return d->data->data.begin() + d->offset; } ByteVector::ConstIterator ByteVector::begin() const { - return d->data.begin(); + return d->data->data.begin() + d->offset; } ByteVector::Iterator ByteVector::end() { - return d->data.end(); + return d->data->data.begin() + d->offset + d->length; } ByteVector::ConstIterator ByteVector::end() const { - return d->data.end(); + return d->data->data.begin() + d->offset + d->length; +} + +ByteVector::ReverseIterator ByteVector::rbegin() +{ + std::vector &v = d->data->data; + return v.rbegin() + (v.size() - (d->offset + d->length)); +} + +ByteVector::ConstReverseIterator ByteVector::rbegin() const +{ + std::vector &v = d->data->data; + return v.rbegin() + (v.size() - (d->offset + d->length)); +} + +ByteVector::ReverseIterator ByteVector::rend() +{ + std::vector &v = d->data->data; + return v.rbegin() + (v.size() - d->offset); +} + +ByteVector::ConstReverseIterator ByteVector::rend() const +{ + std::vector &v = d->data->data; + return v.rbegin() + (v.size() - d->offset); } bool ByteVector::isNull() const { - return d == null.d; + return (d == null.d); } bool ByteVector::isEmpty() const { - return d->data.size() == 0; + return (d->length == 0); } TagLib::uint ByteVector::checksum() const @@ -591,42 +743,41 @@ TagLib::uint ByteVector::checksum() const TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const { - return toNumber(d->data, mostSignificantByteFirst); + return toNumber(*this, mostSignificantByteFirst); } short ByteVector::toShort(bool mostSignificantByteFirst) const { - return toNumber(d->data, mostSignificantByteFirst); + return toNumber(*this, mostSignificantByteFirst); } unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const { - return toNumber(d->data, mostSignificantByteFirst); + return toNumber(*this, mostSignificantByteFirst); } long long ByteVector::toLongLong(bool mostSignificantByteFirst) const { - return toNumber(d->data, mostSignificantByteFirst); + return toNumber(*this, mostSignificantByteFirst); } const char &ByteVector::operator[](int index) const { - return d->data[index]; + return d->data->data[d->offset + index]; } char &ByteVector::operator[](int index) { detach(); - - return d->data[index]; + return d->data->data[d->offset + index]; } bool ByteVector::operator==(const ByteVector &v) const { - if(d->size != v.d->size) + if(size() != v.size()) return false; - return ::memcmp(data(), v.data(), size()) == 0; + return (::memcmp(data(), v.data(), size()) == 0); } bool ByteVector::operator!=(const ByteVector &v) const @@ -636,10 +787,10 @@ bool ByteVector::operator!=(const ByteVector &v) const bool ByteVector::operator==(const char *s) const { - if(d->size != ::strlen(s)) + if(size() != ::strlen(s)) return false; - return ::memcmp(data(), s, d->size) == 0; + return (::memcmp(data(), s, size()) == 0); } bool ByteVector::operator!=(const char *s) const @@ -649,8 +800,7 @@ bool ByteVector::operator!=(const char *s) const bool ByteVector::operator<(const ByteVector &v) const { - int result = ::memcmp(data(), v.data(), d->size < v.d->size ? d->size : v.d->size); - + const int result = ::memcmp(data(), v.data(), std::min(size(), v.size())); if(result != 0) return result < 0; else @@ -697,12 +847,12 @@ ByteVector &ByteVector::operator=(const char *data) ByteVector ByteVector::toHex() const { ByteVector encoded(size() * 2); + char *p = encoded.data(); - uint j = 0; for(uint i = 0; i < size(); i++) { - unsigned char c = d->data[i]; - encoded[j++] = hexTable[(c >> 4) & 0x0F]; - encoded[j++] = hexTable[(c ) & 0x0F]; + unsigned char c = data()[i]; + *p++ = hexTable[(c >> 4) & 0x0F]; + *p++ = hexTable[(c ) & 0x0F]; } return encoded; @@ -714,9 +864,15 @@ ByteVector ByteVector::toHex() const void ByteVector::detach() { + if(d->data->count() > 1) { + d->data->deref(); + d->data = new DataPrivate(d->data->data, d->offset, d->length); + d->offset = 0; + } + if(d->count() > 1) { d->deref(); - d = new ByteVectorPrivate(d->data); + d = new ByteVectorPrivate(d->data->data, d->offset, d->length); } } diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index 0c583263..ca810130 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -48,6 +48,8 @@ namespace TagLib { #ifndef DO_NOT_DOCUMENT typedef std::vector::iterator Iterator; typedef std::vector::const_iterator ConstIterator; + typedef std::vector::reverse_iterator ReverseIterator; + typedef std::vector::const_reverse_iterator ConstReverseIterator; #endif /*! @@ -66,6 +68,11 @@ namespace TagLib { */ ByteVector(const ByteVector &v); + /*! + * Contructs a byte vector that is a copy of \a v. + */ + ByteVector(const ByteVector &v, uint offset, uint length); + /*! * Contructs a byte vector that contains \a c. */ @@ -135,6 +142,14 @@ namespace TagLib { */ int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; + /*! + * Searches the char for \a c starting at \a offset and returns + * the offset. Returns \a npos if the pattern was not found. If \a byteAlign is + * specified the pattern will only be matched if it starts on a byte divisible + * by \a byteAlign (starting from \a offset). + */ + int find(char c, uint offset = 0, int byteAlign = 1) const; + /*! * Searches the ByteVector for \a pattern starting from either the end of the * vector or \a offset and returns the offset. Returns -1 if the pattern was @@ -222,6 +237,26 @@ namespace TagLib { */ ConstIterator end() const; + /*! + * Returns a ReverseIterator that points to the front of the vector. + */ + ReverseIterator rbegin(); + + /*! + * Returns a ConstReverseIterator that points to the front of the vector. + */ + ConstReverseIterator rbegin() const; + + /*! + * Returns a ReverseIterator that points to the back of the vector. + */ + ReverseIterator rend(); + + /*! + * Returns a ConstReverseIterator that points to the back of the vector. + */ + ConstReverseIterator rend() const; + /*! * Returns true if the vector is null. * @@ -413,7 +448,6 @@ namespace TagLib { class ByteVectorPrivate; ByteVectorPrivate *d; }; - } /*! From b52cd44c2571b5a94ce7143460d4f4a73446e223 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 15 Apr 2013 05:03:54 +0900 Subject: [PATCH 08/15] Some improvements of String --- taglib/toolkit/taglib.h | 12 + taglib/toolkit/tstring.cpp | 628 ++++++++++++++++++++----------------- taglib/toolkit/tstring.h | 41 ++- taglib/toolkit/unicode.h | 4 +- 4 files changed, 389 insertions(+), 296 deletions(-) diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index e941ca78..ed82b0fe 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -63,6 +63,18 @@ # define TAGLIB_ATOMIC_GCC #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 +*/ +#endif + //! A namespace for all TagLib related classes and functions /*! diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 292f3533..42505cbe 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -23,8 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +// This class assumes that std::basic_string has a contiguous and null-terminated buffer. +// + #include "tstring.h" -#include "unicode.h" #include "tdebug.h" #include "tstringlist.h" @@ -32,167 +34,170 @@ #include -namespace TagLib { +// Determine if the compiler supports codecvt. + +#if (defined(_MSC_VER) && _MSC_VER >= 1600) +# define TAGLIB_USE_CODECVT +#endif + +#ifdef TAGLIB_USE_CODECVT +# include +typedef std::codecvt_utf8_utf16 utf8_utf16_t; +#else +# include "unicode.h" +#endif + +namespace { inline unsigned short byteSwap(unsigned short x) { +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + + return _byteswap_ushort(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) + + TagLib::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 } -using namespace TagLib; +namespace TagLib { class String::StringPrivate : public RefCounter { public: - StringPrivate(const wstring &s) : - RefCounter(), - data(s), - CString(0) {} - - StringPrivate() : - RefCounter(), - CString(0) {} - - ~StringPrivate() { - delete [] CString; - } - - wstring data; + StringPrivate(const wstring &s) : RefCounter(), data(s) {} + StringPrivate() : RefCounter() {} /*! - * This is only used to hold the a pointer to the most recent value of - * toCString. + * Stores string in UTF-16. The byte order depends on the CPU endian. */ - char *CString; + TagLib::wstring data; + + /*! + * This is only used to hold the the most recent value of toCString(). + */ + std::string cstring; }; String String::null; //////////////////////////////////////////////////////////////////////////////// -String::String() +String::String() + : d(new StringPrivate()) { - d = new StringPrivate; } -String::String(const String &s) : d(s.d) +String::String(const String &s) + : d(s.d) { d->ref(); } String::String(const std::string &s, Type t) + : d(new StringPrivate()) { - d = new StringPrivate; - - if(t == UTF16 || t == UTF16BE || t == UTF16LE) { + if(t == Latin1) + copyFromLatin1(&s[0], s.length()); + else if(t == String::UTF8) + copyFromUTF8(&s[0], s.length()); + else { debug("String::String() -- A std::string should not contain UTF16."); - return; } - - int length = s.length(); - d->data.resize(length); - wstring::iterator targetIt = d->data.begin(); - - for(std::string::const_iterator it = s.begin(); it != s.end(); it++) { - *targetIt = uchar(*it); - ++targetIt; - } - - prepare(t); } String::String(const wstring &s, Type t) + : d(new StringPrivate()) { - d = new StringPrivate(s); - prepare(t); + if(t == UTF16 || t == UTF16BE || t == UTF16LE) + copyFromUTF16(s.c_str(), s.length(), t); + else { + debug("String::String() -- A TagLib::wstring should not contain Latin1 or UTF-8."); + } } String::String(const wchar_t *s, Type t) + : d(new StringPrivate()) { - d = new StringPrivate(s); - prepare(t); + if(t == UTF16 || t == UTF16BE || t == UTF16LE) + copyFromUTF16(s, ::wcslen(s), t); + else { + debug("String::String() -- A const wchar_t * should not contain Latin1 or UTF-8."); + } } String::String(const char *s, Type t) + : d(new StringPrivate()) { - d = new StringPrivate; - - if(t == UTF16 || t == UTF16BE || t == UTF16LE) { + if(t == Latin1) + copyFromLatin1(s, ::strlen(s)); + else if(t == String::UTF8) + copyFromUTF8(s, ::strlen(s)); + else { debug("String::String() -- A const char * should not contain UTF16."); - return; } - - int length = ::strlen(s); - d->data.resize(length); - - wstring::iterator targetIt = d->data.begin(); - - for(int i = 0; i < length; i++) { - *targetIt = uchar(s[i]); - ++targetIt; - } - - prepare(t); } String::String(wchar_t c, Type t) + : d(new StringPrivate()) { - d = new StringPrivate; - d->data += c; - prepare(t); + if(t == UTF16 || t == UTF16BE || t == UTF16LE) + copyFromUTF16(&c, 1, t); + else { + debug("String::String() -- A const wchar_t should not contain Latin1 or UTF-8."); + } } String::String(char c, Type t) + : d(new StringPrivate()) { - d = new StringPrivate; - - if(t == UTF16 || t == UTF16BE || t == UTF16LE) { - debug("String::String() -- A std::string should not contain UTF16."); - return; + if(t == Latin1 || t == UTF8) { + d->data.resize(1); + d->data[0] = static_cast(c); + } + else { + debug("String::String() -- A char should not contain UTF16."); } - - d->data += uchar(c); - prepare(t); } String::String(const ByteVector &v, Type t) + : d(new StringPrivate()) { - d = new StringPrivate; - if(v.isEmpty()) return; - if(t == Latin1 || t == UTF8) { - - int length = 0; - d->data.resize(v.size()); - wstring::iterator targetIt = d->data.begin(); - for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) { - *targetIt = uchar(*it); - ++targetIt; - ++length; - } - d->data.resize(length); - } - else { - d->data.resize(v.size() / 2); - wstring::iterator targetIt = d->data.begin(); - - for(ByteVector::ConstIterator it = v.begin(); - it != v.end() && it + 1 != v.end() && combine(*it, *(it + 1)); - it += 2) - { - *targetIt = combine(*it, *(it + 1)); - ++targetIt; - } - } - prepare(t); + if(t == Latin1) + copyFromLatin1(v.data(), v.size()); + else if(t == UTF8) + copyFromUTF8(v.data(), v.size()); + else + copyFromUTF16(v.data(), v.size(), t); } //////////////////////////////////////////////////////////////////////////////// @@ -206,46 +211,50 @@ String::~String() std::string String::to8Bit(bool unicode) const { std::string s; - s.resize(d->data.size()); if(!unicode) { + s.resize(d->data.size()); + std::string::iterator targetIt = s.begin(); for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - *targetIt = char(*it); + *targetIt = static_cast(*it); ++targetIt; } - return s; } + else { + s.resize(d->data.size() * 4 + 1); - const int outputBufferSize = d->data.size() * 3 + 1; +#ifdef TAGLIB_USE_CODECVT - Unicode::UTF16 *sourceBuffer = new Unicode::UTF16[d->data.size() + 1]; - Unicode::UTF8 *targetBuffer = new Unicode::UTF8[outputBufferSize]; + std::mbstate_t st = 0; + const wchar_t *source; + char *target; + std::codecvt_base::result result = utf8_utf16_t().out( + st, &d->data[0], &d->data[d->data.size()], source, &s[0], &s[s.size()], target); - for(unsigned int i = 0; i < d->data.size(); i++) - sourceBuffer[i] = Unicode::UTF16(d->data[i]); + if(result != utf8_utf16_t::ok) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } - const Unicode::UTF16 *source = sourceBuffer; - Unicode::UTF8 *target = targetBuffer; +#else - Unicode::ConversionResult result = - Unicode::ConvertUTF16toUTF8(&source, sourceBuffer + d->data.size(), - &target, targetBuffer + outputBufferSize, - Unicode::lenientConversion); + const Unicode::UTF16 *source = &d->data[0]; + Unicode::UTF8 *target = reinterpret_cast(&s[0]); - if(result != Unicode::conversionOK) { - debug("String::to8Bit() - Unicode conversion error."); + Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( + &source, source + d->data.size(), + &target, target + s.size(), + Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::to8Bit() - Unicode conversion error."); + } + +#endif + + s.resize(::strlen(s.c_str())); } - int newSize = target - targetBuffer; - s.resize(newSize); - targetBuffer[newSize] = 0; - - s = (char *) targetBuffer; - - delete [] sourceBuffer; - delete [] targetBuffer; - return s; } @@ -256,22 +265,8 @@ TagLib::wstring String::toWString() const const char *String::toCString(bool unicode) const { - delete [] d->CString; - - std::string buffer = to8Bit(unicode); - d->CString = new char[buffer.size() + 1]; - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later - - strcpy_s(d->CString, buffer.size() + 1, buffer.c_str()); - -#else - - strcpy(d->CString, buffer.c_str()); - -#endif - - return d->CString; + d->cstring = to8Bit(unicode); + return d->cstring.c_str(); } String::Iterator String::begin() @@ -296,23 +291,12 @@ String::ConstIterator String::end() const int String::find(const String &s, int offset) const { - wstring::size_type position = d->data.find(s.d->data, offset); - - if(position != wstring::npos) - return position; - else - return -1; + return d->data.find(s.d->data, offset); } int String::rfind(const String &s, int offset) const { - wstring::size_type position = - d->data.rfind(s.d->data, offset == -1 ? wstring::npos : offset); - - if(position != wstring::npos) - return position; - else - return -1; + return d->data.rfind(s.d->data, offset); } StringList String::split(const String &separator) const @@ -345,9 +329,7 @@ bool String::startsWith(const String &s) const String String::substr(uint position, uint n) const { - String s; - s.d->data = d->data.substr(position, n); - return s; + return String(d->data.substr(position, n)); } String &String::append(const String &s) @@ -395,67 +377,102 @@ bool String::isNull() const ByteVector String::data(Type t) const { - ByteVector v; - - switch(t) { - + switch(t) + { case Latin1: - { - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) - v.append(char(*it)); - break; - } + { + ByteVector v(size(), 0); + char *p = v.data(); + + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) + *p++ = static_cast(*it); + + return v; + } case UTF8: - { - std::string s = to8Bit(true); - v.setData(s.c_str(), s.length()); - break; - } + { + ByteVector v(size() * 4 + 1, 0); + +#ifdef TAGLIB_USE_CODECVT + + std::mbstate_t st = 0; + const wchar_t *source; + char *target; + std::codecvt_base::result result = utf8_utf16_t().out( + st, &d->data[0], &d->data[d->data.size()], source, v.data(), v.data() + v.size(), target); + + if(result != utf8_utf16_t::ok) { + debug("String::data() - Unicode conversion error."); + } + +#else + + const Unicode::UTF16 *source = &d->data[0]; + Unicode::UTF8 *target = reinterpret_cast(v.data()); + + Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( + &source, source + d->data.size(), + &target, target + v.size(), + Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::data() - Unicode conversion error."); + } + +#endif + + v.resize(::strlen(v.data())); + + return v; + } case UTF16: - { - // Assume that if we're doing UTF16 and not UTF16BE that we want little - // endian encoding. (Byte Order Mark) + { + ByteVector v(2 + size() * 2, 0); + char *p = v.data(); - v.append(char(0xff)); - v.append(char(0xfe)); + // Assume that if we're doing UTF16 and not UTF16BE that we want little + // endian encoding. (Byte Order Mark) - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + *p++ = '\xff'; + *p++ = '\xfe'; - char c1 = *it & 0xff; - char c2 = *it >> 8; + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + *p++ = static_cast(*it & 0xff); + *p++ = static_cast(*it >> 8); + } - v.append(c1); - v.append(c2); + return v; } - break; - } case UTF16BE: - { - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + { + ByteVector v(size() * 2, 0); + char *p = v.data(); - char c1 = *it >> 8; - char c2 = *it & 0xff; + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + *p++ = static_cast(*it >> 8); + *p++ = static_cast(*it & 0xff); + } - v.append(c1); - v.append(c2); + return v; } - break; - } case UTF16LE: - { - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + { + ByteVector v(size() * 2, 0); + char *p = v.data(); - char c1 = *it & 0xff; - char c2 = *it >> 8; + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + *p++ = static_cast(*it & 0xff); + *p++ = static_cast(*it >> 8); + } - v.append(c1); - v.append(c2); + return v; + } + default: + { + debug("String::data() - Invalid Type value."); + return ByteVector(); } - break; } - } - - return v; } int String::toInt() const @@ -560,7 +577,6 @@ String String::number(int n) // static TagLib::wchar &String::operator[](int i) { detach(); - return d->data[i]; } @@ -638,14 +654,7 @@ String &String::operator=(const std::string &s) delete d; d = new StringPrivate; - - d->data.resize(s.size()); - - wstring::iterator targetIt = d->data.begin(); - for(std::string::const_iterator it = s.begin(); it != s.end(); it++) { - *targetIt = uchar(*it); - ++targetIt; - } + copyFromLatin1(s.c_str(), s.length()); return *this; } @@ -690,15 +699,7 @@ String &String::operator=(const char *s) delete d; d = new StringPrivate; - - int length = ::strlen(s); - d->data.resize(length); - - wstring::iterator targetIt = d->data.begin(); - for(int i = 0; i < length; i++) { - *targetIt = uchar(s[i]); - ++targetIt; - } + copyFromLatin1(s, ::strlen(s)); return *this; } @@ -709,20 +710,10 @@ String &String::operator=(const ByteVector &v) delete d; d = new StringPrivate; - d->data.resize(v.size()); - wstring::iterator targetIt = d->data.begin(); - - uint i = 0; - - for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) { - *targetIt = uchar(*it); - ++targetIt; - ++i; - } + copyFromLatin1(v.data(), v.size()); // If we hit a null in the ByteVector, shrink the string again. - - d->data.resize(i); + d->data.resize(::wcslen(d->data.c_str())); return *this; } @@ -748,68 +739,132 @@ void String::detach() // private members //////////////////////////////////////////////////////////////////////////////// -void String::prepare(Type t) +void String::copyFromLatin1(const char *s, size_t length) { - switch(t) { - case UTF16: - { - if(d->data.size() >= 1 && (d->data[0] == 0xfeff || d->data[0] == 0xfffe)) { - bool swap = d->data[0] != 0xfeff; - d->data.erase(d->data.begin(), d->data.begin() + 1); - if(swap) { - for(uint i = 0; i < d->data.size(); i++) - d->data[i] = byteSwap((unsigned short)d->data[i]); - } - } + d->data.resize(length); + + for(size_t i = 0; i < length; ++i) + d->data[i] = static_cast(s[i]); +} + +void String::copyFromUTF8(const char *s, size_t length) +{ + d->data.resize(length); + +#ifdef TAGLIB_USE_CODECVT + + std::mbstate_t st = 0; + const char *source; + wchar_t *target; + std::codecvt_base::result result = utf8_utf16_t().in( + st, s, s + length, source, &d->data[0], &d->data[d->data.size()], target); + + if(result != utf8_utf16_t::ok) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#else + + const Unicode::UTF8 *source = reinterpret_cast(s); + Unicode::UTF16 *target = &d->data[0]; + + Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( + &source, source + length, + &target, target + length, + Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#endif + + d->data.resize(::wcslen(d->data.c_str())); +} + +void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) +{ + bool swap; + if(t == UTF16) { + if(length >= 1 && s[0] == 0xfeff) + swap = false; // Same as CPU endian. No need to swap bytes. + else if(length >= 1 && s[0] == 0xfffe) + swap = true; // Not same as CPU endian. Need to swap bytes. else { - debug("String::prepare() - Invalid UTF16 string."); - d->data.erase(d->data.begin(), d->data.end()); - } - break; - } - case UTF8: - { - int bufferSize = d->data.size() + 1; - Unicode::UTF8 *sourceBuffer = new Unicode::UTF8[bufferSize]; - Unicode::UTF16 *targetBuffer = new Unicode::UTF16[bufferSize]; - - unsigned int i = 0; - for(; i < d->data.size(); i++) - sourceBuffer[i] = Unicode::UTF8(d->data[i]); - sourceBuffer[i] = 0; - - const Unicode::UTF8 *source = sourceBuffer; - Unicode::UTF16 *target = targetBuffer; - - Unicode::ConversionResult result = - Unicode::ConvertUTF8toUTF16(&source, sourceBuffer + bufferSize, - &target, targetBuffer + bufferSize, - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::prepare() - Unicode conversion error."); + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; } - int newSize = target != targetBuffer ? target - targetBuffer - 1 : 0; - d->data.resize(newSize); - - for(int i = 0; i < newSize; i++) - d->data[i] = targetBuffer[i]; - - delete [] sourceBuffer; - delete [] targetBuffer; - - break; + s++; + length--; } - case UTF16LE: - { - for(uint i = 0; i < d->data.size(); i++) - d->data[i] = byteSwap((unsigned short)d->data[i]); - break; + else + swap = (t != WCharByteOrder); + + d->data.resize(length); + memcpy(&d->data[0], s, length * sizeof(wchar_t)); + + if(swap) { + for(size_t i = 0; i < length; ++i) + d->data[i] = byteSwap(static_cast(s[i])); } - default: - break; +} + +template +void String::internalCopyFromUTF16(const char *s, size_t length, Type t) +{ + // Non specialized version. Used where sizeof(wchar_t) != 2. + + bool swap; + if(t == UTF16) { + if(length >= 2 && *reinterpret_cast(s) == 0xfeff) + swap = false; // Same as CPU endian. No need to swap bytes. + else if(length >= 2 && *reinterpret_cast(s) == 0xfffe) + swap = true; // Not same as CPU endian. Need to swap bytes. + else { + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; + } + + s += 2; + length -= 2; } + else + swap = (t != WCharByteOrder); + + d->data.resize(length / 2); + for(size_t i = 0; i < length / 2; ++i) { + d->data[i] = swap ? combine(*s, *(s + 1)) : combine(*(s + 1), *s); + s += 2; + } +} + +template <> +void String::internalCopyFromUTF16<2>(const char *s, size_t length, Type t) +{ + // Specialized version for where sizeof(wchar_t) == 2. + + copyFromUTF16(reinterpret_cast(s), length / 2, t); +} + +void String::copyFromUTF16(const char *s, size_t length, Type t) +{ + internalCopyFromUTF16(s, length, t); +} + +#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 } //////////////////////////////////////////////////////////////////////////////// @@ -818,27 +873,28 @@ void String::prepare(Type t) const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2) { - String s(s1); + TagLib::String s(s1); s.append(s2); return s; } const TagLib::String operator+(const char *s1, const TagLib::String &s2) { - String s(s1); + TagLib::String s(s1); s.append(s2); return s; } const TagLib::String operator+(const TagLib::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 759a175a..150d7c37 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -135,12 +135,12 @@ namespace TagLib { /*! * Makes a deep copy of the data in \a s. */ - String(const wstring &s, Type t = UTF16BE); + String(const wstring &s, Type t = WCharByteOrder); /*! * Makes a deep copy of the data in \a s. */ - String(const wchar_t *s, Type t = UTF16BE); + String(const wchar_t *s, Type t = WCharByteOrder); /*! * Makes a deep copy of the data in \a c. @@ -451,17 +451,42 @@ namespace TagLib { private: /*! - * This checks to see if the string is in \e UTF-16 (with BOM) or \e UTF-8 - * format and if so converts it to \e UTF-16BE for internal use. \e Latin1 - * does not require conversion since it is a subset of \e UTF-16BE and - * \e UTF16-BE requires no conversion since it is used internally. + * Converts a \e Latin-1 string into \e UTF-16(without BOM/CPU byte order) + * and copies it to the internal buffer. */ - void prepare(Type t); + void copyFromLatin1(const char *s, size_t length); + + /*! + * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order) + * and copies it to the internal buffer. + */ + void copyFromUTF8(const char *s, size_t length); + + /*! + * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into + * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. + */ + void copyFromUTF16(const wchar_t *s, size_t length, Type t); + + /*! + * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into + * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. + */ + void copyFromUTF16(const char *s, size_t length, Type t); + + template + void internalCopyFromUTF16(const char *s, size_t length, Type t); + + /*! + * Indicates which byte order of UTF-16 is used to store strings internally. + * + * \note \e String::UTF16BE or \e String::UTF16LE + */ + static const Type WCharByteOrder; class StringPrivate; StringPrivate *d; }; - } /*! diff --git a/taglib/toolkit/unicode.h b/taglib/toolkit/unicode.h index cf7eb3c5..b9de0ea2 100644 --- a/taglib/toolkit/unicode.h +++ b/taglib/toolkit/unicode.h @@ -115,8 +115,8 @@ namespace Unicode { typedef unsigned long UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ +typedef wchar_t UTF16; /* TagLib assumes that wchar_t is sufficient for UTF-16. */ +typedef unsigned char UTF8; /* typically 8 bits */ typedef unsigned char Boolean; /* 0 or 1 */ typedef enum { From 86142343eea3c92c3a94b86b022f637da15e094f Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 15 Apr 2013 05:23:39 +0900 Subject: [PATCH 09/15] Fix VC++ specific warnings --- taglib/mp4/mp4tag.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index 3c22f062..17ab766f 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -895,8 +895,8 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props) d->items[name] = MP4::Item(value); } else if(it->first == "COMPILATION") { - bool value = it->second.front().toInt(); - d->items[name] = MP4::Item(value > 0); + bool value = (it->second.front().toInt() != 0); + d->items[name] = MP4::Item(value); } else { d->items[name] = it->second; From 4a85e1e1ca4af7c4453b59b2985702df96660f42 Mon Sep 17 00:00:00 2001 From: Jingmin Wei Date: Mon, 15 Apr 2013 09:46:08 +0200 Subject: [PATCH 10/15] Allow the second byte of MPEG header to contain 0xFF 0xFF in the second byte means MPEG Version 1, Layer I, no CRC protection. http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html --- taglib/mpeg/mpegfile.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index 51cb5784..f765befb 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -656,9 +656,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 From a3352fd899c07c30b52855306159fc56a4c92aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Mon, 15 Apr 2013 10:12:02 +0200 Subject: [PATCH 11/15] Use the first instance of a MP4 atom (#126) When a file contains multiple MP4 atoms with the same name, use the first one. This is consistent with iTunes and other popular software. --- taglib/mp4/mp4tag.cpp | 33 +++++++++++++++++++++------------ taglib/mp4/mp4tag.h | 2 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index 17ab766f..3deb84b3 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -159,7 +159,7 @@ MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - d->items.insert(atom->name, (int)data[0].toShort()); + addItem(atom->name, (int)data[0].toShort()); } } @@ -168,7 +168,7 @@ MP4::Tag::parseUInt(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - d->items.insert(atom->name, data[0].toUInt()); + addItem(atom->name, data[0].toUInt()); } } @@ -177,7 +177,7 @@ MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { - d->items.insert(atom->name, data[0].toLongLong()); + addItem(atom->name, data[0].toLongLong()); } } @@ -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)); } } @@ -196,8 +196,8 @@ MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file) ByteVectorList data = parseData(atom, file); if(data.size()) { int idx = (int)data[0].toShort(); - if(!d->items.contains("\251gen") && idx > 0) { - d->items.insert("\251gen", StringList(ID3v1::genre(idx - 1))); + if(idx > 0) { + addItem("\251gen", StringList(ID3v1::genre(idx - 1))); } } } @@ -209,7 +209,7 @@ MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file) if(data.size()) { int a = data[0].mid(2, 2).toShort(); int b = data[0].mid(4, 2).toShort(); - d->items.insert(atom->name, MP4::Item(a, b)); + addItem(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 @@ -910,3 +910,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 0e1d0676..48d71fcb 100644 --- a/taglib/mp4/mp4tag.h +++ b/taglib/mp4/mp4tag.h @@ -105,6 +105,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; }; From 53c5a97b4c028c557bdc7b883fdef74f972d22c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Mon, 15 Apr 2013 10:45:33 +0200 Subject: [PATCH 12/15] Add tests for newline handling in String (#125) --- tests/test_string.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_string.cpp b/tests/test_string.cpp index 1e37d7a2..4a58c277 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(uint(7), String(cr).size()); + CPPUNIT_ASSERT_EQUAL(uint(7), String(lf).size()); + CPPUNIT_ASSERT_EQUAL(uint(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); From f5462e3e19278a8105da8ece407eb0ab953d7595 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 16 Apr 2013 00:09:18 +0900 Subject: [PATCH 13/15] Add cross-platform byte order conversions --- taglib/CMakeLists.txt | 2 + taglib/toolkit/taglib.h | 36 +++++++- taglib/toolkit/tbyteswap.cpp | 160 +++++++++++++++++++++++++++++++++ taglib/toolkit/tbyteswap.h | 49 ++++++++++ taglib/toolkit/tbytevector.cpp | 49 +--------- taglib/toolkit/tstring.cpp | 17 +--- 6 files changed, 249 insertions(+), 64 deletions(-) create mode 100644 taglib/toolkit/tbyteswap.cpp create mode 100644 taglib/toolkit/tbyteswap.h diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index 72712ca2..a940caf5 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -50,6 +50,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 @@ -289,6 +290,7 @@ set(toolkit_SRCS toolkit/tfilestream.cpp toolkit/tdebug.cpp toolkit/tpropertymap.cpp + toolkit/tbyteswap.cpp toolkit/unicode.cpp ) diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index ed82b0fe..696174e9 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -43,6 +43,7 @@ #endif #include +#include #ifdef __APPLE__ # include @@ -75,6 +76,30 @@ */ #endif +// 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 + //! A namespace for all TagLib related classes and functions /*! @@ -89,10 +114,13 @@ namespace TagLib { class String; - typedef wchar_t wchar; - typedef unsigned char uchar; - typedef unsigned short ushort; - typedef unsigned int uint; + 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; + typedef unsigned long long ulonglong; + + // long/ulong can be either 32-bit or 64-bit wide. typedef unsigned long ulong; /*! diff --git a/taglib/toolkit/tbyteswap.cpp b/taglib/toolkit/tbyteswap.cpp new file mode 100644 index 00000000..cf0c9b9b --- /dev/null +++ b/taglib/toolkit/tbyteswap.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + 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 + +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 + } +} diff --git a/taglib/toolkit/tbyteswap.h b/taglib/toolkit/tbyteswap.h new file mode 100644 index 00000000..ed20125c --- /dev/null +++ b/taglib/toolkit/tbyteswap.h @@ -0,0 +1,49 @@ +/*************************************************************************** + 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); +} + +#endif diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 89785d04..63aad50f 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -24,23 +24,12 @@ ***************************************************************************/ #include - #include #include - #include -#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(_M_IX86) || defined(_M_X64)) -# define TAGLIB_MSC_BYTESWAP -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -# define TAGLIB_GCC_BYTESWAP -#endif - -#ifdef TAGLIB_GCC_BYTESWAP -# include -#endif - #include "tbytevector.h" +#include "tbyteswap.h" // This is a bit ugly to keep writing over and over again. @@ -184,8 +173,6 @@ namespace TagLib { return -1; } -#if defined(TAGLIB_MSC_BYTESWAP) || defined(TAGLIB_GCC_BYTESWAP) - template T byteSwap(T x) { @@ -194,52 +181,24 @@ namespace TagLib { return 0; } -#endif - -#ifdef TAGLIB_MSC_BYTESWAP - template <> unsigned short byteSwap(unsigned short x) { - return _byteswap_ushort(x); + return byteSwap16(x); } template <> unsigned int byteSwap(unsigned int x) { - return _byteswap_ulong(x); + return byteSwap32(x); } template <> unsigned long long byteSwap(unsigned long long x) { - return _byteswap_uint64(x); + return byteSwap64(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) { diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 42505cbe..2c80e80c 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -29,9 +29,9 @@ #include "tstring.h" #include "tdebug.h" #include "tstringlist.h" +#include "tbyteswap.h" #include - #include // Determine if the compiler supports codecvt. @@ -49,19 +49,6 @@ typedef std::codecvt_utf8_utf16 utf8_utf16_t; namespace { - inline unsigned short byteSwap(unsigned short x) - { -#if defined(_MSC_VER) && (_MSC_VER >= 1400) - - return _byteswap_ushort(x); - -#else - - return (((x) >> 8) & 0xff) | (((x) & 0xff) << 8); - -#endif - } - inline unsigned short combine(unsigned char c1, unsigned char c2) { return (c1 << 8) | c2; @@ -806,7 +793,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])); } } From 88a0871784542f05b820efa19be28e870acce44d Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Tue, 16 Apr 2013 04:06:29 +0900 Subject: [PATCH 14/15] Bug fix for #132 --- taglib/toolkit/taglib.h | 12 - taglib/toolkit/tbyteswap.cpp | 32 +++ taglib/toolkit/tbyteswap.h | 6 + taglib/toolkit/tbytevector.cpp | 389 ++++++++++++++++----------------- taglib/toolkit/tbytevector.h | 5 + taglib/toolkit/tstring.cpp | 32 +-- 6 files changed, 233 insertions(+), 243 deletions(-) diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h index 696174e9..dd4ee69d 100755 --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -64,18 +64,6 @@ # define TAGLIB_ATOMIC_GCC #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 -*/ -#endif - // Check the widths of integral types. #if UCHAR_MAX != 255U diff --git a/taglib/toolkit/tbyteswap.cpp b/taglib/toolkit/tbyteswap.cpp index cf0c9b9b..7aeea902 100644 --- a/taglib/toolkit/tbyteswap.cpp +++ b/taglib/toolkit/tbyteswap.cpp @@ -59,6 +59,20 @@ #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 + +#endif + + namespace TagLib { ushort byteSwap16(ushort x) @@ -155,6 +169,24 @@ namespace TagLib | ((x & 0x000000000000ff00ull) << 40) | ((x & 0x00000000000000ffull) << 56); +#endif + } + + bool isLittleEndianSystem() + { +#if defined(TAGLIB_LITTLE_ENDIAN) + + return true; + +#elif defined(TAGLIB_BIG_ENDIAN) + + return false; + +#else + + ushort x = 1; + return (*reinterpret_cast(&x) == 1); + #endif } } diff --git a/taglib/toolkit/tbyteswap.h b/taglib/toolkit/tbyteswap.h index ed20125c..6121414c 100644 --- a/taglib/toolkit/tbyteswap.h +++ b/taglib/toolkit/tbyteswap.h @@ -44,6 +44,12 @@ namespace TagLib * Converts the byte order of \a x as a 64-bit unsigned integer. */ ulonglong byteSwap64(ulonglong x); + + /*! + * Detects the system byte order. + * Returns \a true if little endian, \a false if big endian. + */ + bool isLittleEndianSystem(); } #endif diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 63aad50f..510e6cf6 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -34,226 +34,208 @@ // 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 - int findChar( - const TIterator dataBegin, const TIterator dataEnd, - char c, uint offset, int byteAlign) - { - const size_t dataSize = dataEnd - dataBegin; - if(dataSize == 0 || offset > dataSize - 1) - return -1; - - // n % 0 is invalid - - if(byteAlign == 0) - return -1; - - 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 +int findChar( + const TIterator dataBegin, const TIterator dataEnd, + char c, uint offset, int byteAlign) +{ + const size_t dataSize = dataEnd - dataBegin; + if(dataSize == 0 || offset > dataSize - 1) return -1; + + // n % 0 is invalid + + if(byteAlign == 0) + return -1; + + 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 - int findVector( - const TIterator dataBegin, const TIterator dataEnd, - const TIterator patternBegin, const TIterator patternEnd, - uint offset, int byteAlign) + return -1; +} + +/*! + * A templatized KMP find that works with the types + * std::vector::iterator and std::vector::reverse_iterator. + */ +template +int findVector( + const TIterator dataBegin, const TIterator dataEnd, + const TIterator patternBegin, const TIterator patternEnd, + uint offset, int byteAlign) +{ + const size_t dataSize = dataEnd - dataBegin; + const size_t patternSize = patternEnd - patternBegin; + if(patternSize > dataSize || offset > dataSize - 1) + return -1; + + // n % 0 is invalid + + if(byteAlign == 0) + return -1; + + // Special case that 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 -1; + TIterator itBuffer = it; + TIterator itPattern = patternBegin + patternSize - 1; - // n % 0 is invalid - - if(byteAlign == 0) - return -1; - - // Special case that 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 -1; + --itBuffer; + --itPattern; + } } - 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 -1; +} + +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 <> +unsigned short byteSwap(unsigned short x) +{ + return byteSwap16(x); +} + +template <> +unsigned int byteSwap(unsigned int x) +{ + return byteSwap32(x); +} + +template <> +unsigned long long byteSwap(unsigned long long x) +{ + return byteSwap64(x); +} + +template +T toNumber(const ByteVector &v, bool swapBytes) +{ + if(v.isEmpty()) { + debug("toNumber() -- data is empty, returning 0"); return 0; } - template <> - unsigned short byteSwap(unsigned short x) + const size_t size = sizeof(T); + + if(v.size() >= size) { - return byteSwap16(x); + if(swapBytes) + return byteSwap(*reinterpret_cast(v.data())); + else + return *reinterpret_cast(v.data()); } - template <> - unsigned int byteSwap(unsigned int x) - { - return byteSwap32(x); - } + const uint last = v.size() > size ? size - 1 : v.size() - 1; + T sum = 0; + for(uint i = 0; i <= last; i++) + sum |= (T) uchar(v[i]) << ((swapBytes ? last - i : i) * 8); - template <> - unsigned long long byteSwap(unsigned long long x) - { - return byteSwap64(x); - } - - 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 uint last = v.size() > size ? size - 1 : v.size() - 1; - T sum = 0; - for(uint i = 0; i <= last; i++) - sum |= (T) uchar(v[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); - - 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(uint i = 0; i < size; i++) - v[i] = uchar(value >> ((mostSignificantByteFirst ? size - 1 - i : i) * 8) & 0xff); - - return v; - -#endif - } + return sum; } -using namespace TagLib; +template +ByteVector fromNumber(T value, bool swapBytes) +{ + const size_t size = sizeof(T); + + if(swapBytes) + value = byteSwap(value); + + return ByteVector(reinterpret_cast(&value), size); +} class DataPrivate : public RefCounter { @@ -266,7 +248,7 @@ public: : data(v.begin() + offset, v.begin() + offset + length) { } - + DataPrivate(uint len, char c) : data(len, c) { @@ -371,17 +353,17 @@ ByteVector ByteVector::fromCString(const char *s, uint length) ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, (isLittleEndian == mostSignificantByteFirst)); } ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, (isLittleEndian == mostSignificantByteFirst)); } ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) { - return fromNumber(value, mostSignificantByteFirst); + return fromNumber(value, (isLittleEndian == mostSignificantByteFirst)); } //////////////////////////////////////////////////////////////////////////////// @@ -702,22 +684,22 @@ TagLib::uint ByteVector::checksum() const TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); } short ByteVector::toShort(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); } unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); } long long ByteVector::toLongLong(bool mostSignificantByteFirst) const { - return toNumber(*this, mostSignificantByteFirst); + return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); } const char &ByteVector::operator[](int index) const @@ -835,11 +817,18 @@ void ByteVector::detach() } } +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +const bool ByteVector::isLittleEndian = isLittleEndianSystem(); +} + //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// -std::ostream &operator<<(std::ostream &s, const ByteVector &v) +std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v) { for(TagLib::uint i = 0; i < v.size(); i++) s << v[i]; diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index ca810130..d43e3e78 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -445,6 +445,11 @@ namespace TagLib { void detach(); private: + /*! + * Indicates the system endian. \a true if little endian, \a false if big endian. + */ + static const bool isLittleEndian; + class ByteVectorPrivate; ByteVectorPrivate *d; }; diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 2c80e80c..d6e102c3 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -53,24 +53,6 @@ namespace { { return (c1 << 8) | c2; } - -#if !defined(TAGLIB_LITTLE_ENDIAN) && !defined(TAGLIB_BIG_ENDIAN) - - TagLib::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 { @@ -839,19 +821,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; } //////////////////////////////////////////////////////////////////////////////// From 5e6285afab35f1478b463b193054c41e4e47cd5f Mon Sep 17 00:00:00 2001 From: Tsuda kageyu Date: Tue, 16 Apr 2013 05:53:36 +0900 Subject: [PATCH 15/15] Bug fix for #132 --- taglib/toolkit/tbyteswap.cpp | 21 ++++++++++++------- taglib/toolkit/tbyteswap.h | 6 +++--- taglib/toolkit/tbytevector.cpp | 38 ++++++++++++++-------------------- taglib/toolkit/tbytevector.h | 5 ----- taglib/toolkit/tstring.cpp | 2 +- 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/taglib/toolkit/tbyteswap.cpp b/taglib/toolkit/tbyteswap.cpp index 7aeea902..714033e8 100644 --- a/taglib/toolkit/tbyteswap.cpp +++ b/taglib/toolkit/tbyteswap.cpp @@ -70,8 +70,17 @@ || (defined(__clang__) && defined(__BIG_ENDIAN__)) # define TAGLIB_BIG_ENDIAN -#endif +#else +namespace { + bool isLittleEndian() + { + TagLib::ushort x = 1; + return (*reinterpret_cast(&x) == 1); + } +} + +#endif namespace TagLib { @@ -172,21 +181,17 @@ namespace TagLib #endif } - bool isLittleEndianSystem() - { #if defined(TAGLIB_LITTLE_ENDIAN) - return true; + const bool isLittleEndianSystem = true; #elif defined(TAGLIB_BIG_ENDIAN) - return false; + const bool isLittleEndianSystem = false; #else - ushort x = 1; - return (*reinterpret_cast(&x) == 1); + const bool isLittleEndianSystem = isLittleEndianSystem(); #endif - } } diff --git a/taglib/toolkit/tbyteswap.h b/taglib/toolkit/tbyteswap.h index 6121414c..012a3173 100644 --- a/taglib/toolkit/tbyteswap.h +++ b/taglib/toolkit/tbyteswap.h @@ -46,10 +46,10 @@ namespace TagLib ulonglong byteSwap64(ulonglong x); /*! - * Detects the system byte order. - * Returns \a true if little endian, \a false if big endian. + * Indicates the system byte order. + * \a true if little endian, \a false if big endian. */ - bool isLittleEndianSystem(); + extern const bool isLittleEndianSystem; } #endif diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 510e6cf6..31e11d65 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -183,25 +183,25 @@ T byteSwap(T x) } template <> -unsigned short byteSwap(unsigned short x) +ushort byteSwap(ushort x) { return byteSwap16(x); } template <> -unsigned int byteSwap(unsigned int x) +uint byteSwap(uint x) { return byteSwap32(x); } template <> -unsigned long long byteSwap(unsigned long long x) +ulonglong byteSwap(ulonglong x) { return byteSwap64(x); } template -T toNumber(const ByteVector &v, bool swapBytes) +T toNumber(const ByteVector &v, bool mostSignificantByteFirst) { if(v.isEmpty()) { debug("toNumber() -- data is empty, returning 0"); @@ -212,26 +212,26 @@ T toNumber(const ByteVector &v, bool swapBytes) if(v.size() >= size) { - if(swapBytes) + if(isLittleEndianSystem == mostSignificantByteFirst) return byteSwap(*reinterpret_cast(v.data())); else return *reinterpret_cast(v.data()); } - const uint last = v.size() > size ? size - 1 : v.size() - 1; + const uint last = std::min(v.size() - 1, size); T sum = 0; for(uint i = 0; i <= last; i++) - sum |= (T) uchar(v[i]) << ((swapBytes ? last - i : i) * 8); + sum |= (T) uchar(v[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); return sum; } template -ByteVector fromNumber(T value, bool swapBytes) +ByteVector fromNumber(T value, bool mostSignificantByteFirst) { const size_t size = sizeof(T); - if(swapBytes) + if(isLittleEndianSystem == mostSignificantByteFirst) value = byteSwap(value); return ByteVector(reinterpret_cast(&value), size); @@ -353,17 +353,17 @@ ByteVector ByteVector::fromCString(const char *s, uint length) ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) { - return fromNumber(value, (isLittleEndian == mostSignificantByteFirst)); + return fromNumber(value, mostSignificantByteFirst); } ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) { - return fromNumber(value, (isLittleEndian == mostSignificantByteFirst)); + return fromNumber(value, mostSignificantByteFirst); } ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) { - return fromNumber(value, (isLittleEndian == mostSignificantByteFirst)); + return fromNumber(value, mostSignificantByteFirst); } //////////////////////////////////////////////////////////////////////////////// @@ -684,22 +684,22 @@ TagLib::uint ByteVector::checksum() const TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const { - return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); + return toNumber(*this, mostSignificantByteFirst); } short ByteVector::toShort(bool mostSignificantByteFirst) const { - return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); + return toNumber(*this, mostSignificantByteFirst); } unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const { - return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); + return toNumber(*this, mostSignificantByteFirst); } long long ByteVector::toLongLong(bool mostSignificantByteFirst) const { - return toNumber(*this, (isLittleEndian == mostSignificantByteFirst)); + return toNumber(*this, mostSignificantByteFirst); } const char &ByteVector::operator[](int index) const @@ -816,12 +816,6 @@ void ByteVector::detach() d = new ByteVectorPrivate(d->data->data, d->offset, d->length); } } - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -const bool ByteVector::isLittleEndian = isLittleEndianSystem(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index d43e3e78..ca810130 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -445,11 +445,6 @@ namespace TagLib { void detach(); private: - /*! - * Indicates the system endian. \a true if little endian, \a false if big endian. - */ - static const bool isLittleEndian; - class ByteVectorPrivate; ByteVectorPrivate *d; }; diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index d6e102c3..5fe6f45e 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -821,7 +821,7 @@ void String::copyFromUTF16(const char *s, size_t length, Type t) internalCopyFromUTF16(s, length, t); } -const String::Type String::WCharByteOrder = isLittleEndianSystem() ? String::UTF16LE : String::UTF16BE; +const String::Type String::WCharByteOrder = isLittleEndianSystem ? String::UTF16LE : String::UTF16BE; } ////////////////////////////////////////////////////////////////////////////////