diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f29e463..14f00956 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,6 @@ option(BUILD_EXAMPLES "Build the examples" OFF) option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF) -add_definitions(-DHAVE_CONFIG_H) set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/") ## the following are directories where stuff will be installed to diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 790306c3..fa525f7e 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -8,13 +8,18 @@ include(CheckCXXSourceCompiles) include(TestBigEndian) # Determine the CPU byte order. - test_big_endian(TAGLIB_BIG_ENDIAN) if(NOT TAGLIB_BIG_ENDIAN) set(TAGLIB_LITTLE_ENDIAN 1) endif() +# Determine the size of integral types. +check_type_size("short" SIZEOF_SHORT) +check_type_size("int" SIZEOF_INT) +check_type_size("long long" SIZEOF_LONGLONG) +check_type_size("wchar_t" SIZEOF_WCHAR_T) + # Determine whether or not your compiler supports move semantics. check_cxx_source_compiles(" #ifdef __clang__ @@ -25,6 +30,15 @@ check_cxx_source_compiles(" int main() { return func(std::move(1)); } " SUPPORT_MOVE_SEMANTICS) +# Determine if your compiler supports std::wstring. +check_cxx_source_compiles(" + #include + int main() { + std::wstring x(L\"ABC\"); + return 0; + } +" HAVE_STD_WSTRING) + # Determine which kind of byte swap functions your compiler supports. # GCC's __builtin_bswap* should be checked individually @@ -179,13 +193,16 @@ if(NOT HAVE_SNPRINTF) " HAVE_SPRINTF_S) endif() -# Determine whether your compiler supports codecvt header. +# Determine whether your compiler supports codecvt. check_cxx_source_compiles(" -#include -int main() { std::codecvt_utf8_utf16 x; return 0; } -" HAVE_CODECVT) + #include + int main() { + std::codecvt_utf8_utf16 x; + return 0; + } +" HAVE_STD_CODECVT) -# check for libz using the cmake supplied FindZLIB.cmake +# Check for libz using the cmake supplied FindZLIB.cmake find_package(ZLIB) if(ZLIB_FOUND) set(HAVE_ZLIB 1) @@ -193,10 +210,10 @@ else() set(HAVE_ZLIB 0) endif() + set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) message(STATUS "CppUnit not found, disabling tests.") set(BUILD_TESTS OFF) endif() - diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index 205867e2..58c1ff14 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -4,9 +4,18 @@ #cmakedefine TAGLIB_LITTLE_ENDIAN 1 #cmakedefine TAGLIB_BIG_ENDIAN 1 +/* Size of integral types */ +#cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT} +#cmakedefine SIZEOF_INT ${SIZEOF_INT} +#cmakedefine SIZEOF_LONGLONG ${SIZEOF_LONGLONG} +#cmakedefine SIZEOF_WCHAR_T ${SIZEOF_WCHAR_T} + /* Defined if your compiler supports the move semantics */ #cmakedefine SUPPORT_MOVE_SEMANTICS 1 +/* Defined if your compiler supports std::wstring */ +#cmakedefine HAVE_STD_WSTRING 1 + /* Defined if your compiler supports some byte swap functions */ #cmakedefine HAVE_GCC_BYTESWAP_16 1 #cmakedefine HAVE_GCC_BYTESWAP_32 1 @@ -31,10 +40,10 @@ #cmakedefine HAVE_SNPRINTF 1 #cmakedefine HAVE_SPRINTF_S 1 -/* Defined if your compiler has header */ -#cmakedefine HAVE_CODECVT 1 +/* Defined if your compiler supports codecvt */ +#cmakedefine HAVE_STD_CODECVT 1 -/* Define if you have libz */ +/* Defined if you have libz */ #cmakedefine HAVE_ZLIB 1 #cmakedefine NO_ITUNES_HACKS 1 @@ -42,4 +51,3 @@ #cmakedefine WITH_MP4 1 #cmakedefine TESTS_DIR "@TESTS_DIR@" - diff --git a/taglib/ape/apeproperties.cpp b/taglib/ape/apeproperties.cpp index cbb1ac1e..53228cd1 100644 --- a/taglib/ape/apeproperties.cpp +++ b/taglib/ape/apeproperties.cpp @@ -125,7 +125,7 @@ void APE::Properties::read() // Then we read the header common for all versions of APE d->file->seek(offset); - ByteVector commonHeader=d->file->readBlock(6); + ByteVector commonHeader = d->file->readBlock(6); if(!commonHeader.startsWith("MAC ")) return; d->version = commonHeader.toUInt16LE(4); @@ -182,7 +182,7 @@ void APE::Properties::analyzeCurrent() // Read the descriptor d->file->seek(2, File::Current); ByteVector descriptor = d->file->readBlock(44); - uint descriptorBytes = descriptor.toUInt32LE(0); + const uint descriptorBytes = descriptor.toUInt32LE(0); if ((descriptorBytes - 52) > 0) d->file->seek(descriptorBytes - 52, File::Current); @@ -196,9 +196,10 @@ void APE::Properties::analyzeCurrent() d->bitsPerSample = header.toInt16LE(16); //d->compressionLevel = - uint totalFrames = header.toUInt32LE(12); - uint blocksPerFrame = header.toUInt32LE(4); - uint finalFrameBlocks = header.toUInt32LE(8); + const uint totalFrames = header.toUInt32LE(12); + const uint blocksPerFrame = header.toUInt32LE(4); + const uint finalFrameBlocks = header.toUInt32LE(8); + d->sampleFrames = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; d->bitrate = d->length > 0 ? static_cast(d->streamLength * 8L / d->length / 1000) : 0; @@ -207,13 +208,13 @@ void APE::Properties::analyzeCurrent() void APE::Properties::analyzeOld() { ByteVector header = d->file->readBlock(26); - uint totalFrames = header.toUInt32LE(18); + const uint totalFrames = header.toUInt32LE(18); // Fail on 0 length APE files (catches non-finalized APE files) if(totalFrames == 0) return; - short compressionLevel = header.toUInt32LE(0); + const short compressionLevel = header.toUInt32LE(0); uint blocksPerFrame; if(d->version >= 3950) blocksPerFrame = 73728 * 4; @@ -221,6 +222,7 @@ void APE::Properties::analyzeOld() blocksPerFrame = 73728; else blocksPerFrame = 9216; + d->channels = header.toUInt16LE(4); d->sampleRate = header.toUInt32LE(6); const uint finalFrameBlocks = header.toUInt32LE(22); diff --git a/taglib/asf/asfattribute.cpp b/taglib/asf/asfattribute.cpp index 81fb12e3..a626eeb4 100644 --- a/taglib/asf/asfattribute.cpp +++ b/taglib/asf/asfattribute.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - #include #include #include "asfattribute.h" diff --git a/taglib/asf/asffile.cpp b/taglib/asf/asffile.cpp index 3215e7d5..65a4f989 100644 --- a/taglib/asf/asffile.cpp +++ b/taglib/asf/asffile.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include diff --git a/taglib/asf/asfpicture.cpp b/taglib/asf/asfpicture.cpp index 0b4ff60a..3e23dbb7 100644 --- a/taglib/asf/asfpicture.cpp +++ b/taglib/asf/asfpicture.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - #include #include #include "asfattribute.h" @@ -161,7 +157,7 @@ void ASF::Picture::parse(const ByteVector& bytes) return; size_t pos = 0; d->type = (Type)bytes[0]; ++pos; - uint dataLen = bytes.toUInt32LE(pos); pos+=4; + const uint dataLen = bytes.toUInt32LE(pos); pos+=4; const ByteVector nullStringTerminator(2, 0); diff --git a/taglib/asf/asfproperties.cpp b/taglib/asf/asfproperties.cpp index 835cbdf9..11d43b9d 100644 --- a/taglib/asf/asfproperties.cpp +++ b/taglib/asf/asfproperties.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include diff --git a/taglib/asf/asftag.cpp b/taglib/asf/asftag.cpp index 1cbd16eb..70881209 100644 --- a/taglib/asf/asftag.cpp +++ b/taglib/asf/asftag.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include "asftag.h" diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 2d215bce..e7ee7d52 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -27,13 +27,11 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif +#include #ifdef _WIN32 # include -#endif +#endif #include #include @@ -231,8 +229,8 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, #ifdef _WIN32 // Avoids direct conversion from FileName to String - // because String can't accept non-Latin-1 string in char array. - + // because String can't decode strings in local encodings properly. + if(!fileName.wstr().empty()) { const wchar_t *pext = PathFindExtensionW(fileName.wstr().c_str()); if(*pext == L'.') diff --git a/taglib/fileref.h b/taglib/fileref.h index 01e2875c..4d7670c3 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -32,6 +32,10 @@ #include "taglib_export.h" #include "audioproperties.h" +#if _WIN32 +# pragma comment(lib, "shlwapi.lib") +#endif + namespace TagLib { class Tag; diff --git a/taglib/flac/flacmetadatablock.cpp b/taglib/flac/flacmetadatablock.cpp index 7d161c27..17ab05f3 100644 --- a/taglib/flac/flacmetadatablock.cpp +++ b/taglib/flac/flacmetadatablock.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "flacmetadatablock.h" diff --git a/taglib/flac/flacpicture.cpp b/taglib/flac/flacpicture.cpp index 2a0131de..23e17f73 100644 --- a/taglib/flac/flacpicture.cpp +++ b/taglib/flac/flacpicture.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "flacpicture.h" @@ -109,7 +105,7 @@ bool FLAC::Picture::parse(const ByteVector &data) pos += 4; d->numColors = data.toUInt32BE(pos); pos += 4; - uint dataLength = data.toUInt32BE(pos); + const uint dataLength = data.toUInt32BE(pos); pos += 4; if(pos + dataLength > data.size()) { debug("Invalid picture block."); diff --git a/taglib/flac/flacproperties.cpp b/taglib/flac/flacproperties.cpp index 3bf9d6e9..f75eed16 100644 --- a/taglib/flac/flacproperties.cpp +++ b/taglib/flac/flacproperties.cpp @@ -118,7 +118,7 @@ void FLAC::Properties::read() return; } - int pos = 0; + uint pos = 0; // Minimum block size (in samples) pos += 2; @@ -132,7 +132,7 @@ void FLAC::Properties::read() // Maximum frame size (in bytes) pos += 3; - uint flags = d->data.toUInt32BE(pos); + const uint flags = d->data.toUInt32BE(pos); pos += 4; d->sampleRate = flags >> 12; @@ -142,8 +142,8 @@ void FLAC::Properties::read() // The last 4 bits are the most significant 4 bits for the 36 bit // stream length in samples. (Audio files measured in days) - unsigned long long hi = flags & 0xf; - unsigned long long lo = d->data.toUInt32BE(pos); + const ulonglong hi = flags & 0xf; + const ulonglong lo = d->data.toUInt32BE(pos); pos += 4; d->sampleFrames = (hi << 32) | lo; diff --git a/taglib/flac/flacunknownmetadatablock.cpp b/taglib/flac/flacunknownmetadatablock.cpp index 1265affb..dcd5d651 100644 --- a/taglib/flac/flacunknownmetadatablock.cpp +++ b/taglib/flac/flacunknownmetadatablock.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include diff --git a/taglib/mp4/mp4atom.cpp b/taglib/mp4/mp4atom.cpp index d77a69af..393fc9cd 100644 --- a/taglib/mp4/mp4atom.cpp +++ b/taglib/mp4/mp4atom.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include "mp4atom.h" @@ -55,16 +51,16 @@ MP4::Atom::Atom(File *file) length = header.toUInt32BE(0); if (length == 1) { - long long longLength = file->readBlock(8).toInt64BE(0); + const long long longLength = file->readBlock(8).toInt64BE(0); if (longLength >= 8 && longLength <= 0xFFFFFFFF) { - // The atom has a 64-bit length, but it's actually a 32-bit value - length = (long)longLength; + // The atom has a 64-bit length, but it's actually a 32-bit value + length = (long)longLength; } else { - debug("MP4: 64-bit atoms are not supported"); - length = 0; - file->seek(0, File::End); - return; + debug("MP4: 64-bit atoms are not supported"); + length = 0; + file->seek(0, File::End); + return; } } if (length < 8) { diff --git a/taglib/mp4/mp4coverart.cpp b/taglib/mp4/mp4coverart.cpp index f5a9b462..76abf706 100644 --- a/taglib/mp4/mp4coverart.cpp +++ b/taglib/mp4/mp4coverart.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - #include #include #include "mp4coverart.h" diff --git a/taglib/mp4/mp4file.cpp b/taglib/mp4/mp4file.cpp index f6e15e65..11316447 100644 --- a/taglib/mp4/mp4file.cpp +++ b/taglib/mp4/mp4file.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include diff --git a/taglib/mp4/mp4item.cpp b/taglib/mp4/mp4item.cpp index 65f45546..2de06133 100644 --- a/taglib/mp4/mp4item.cpp +++ b/taglib/mp4/mp4item.cpp @@ -23,13 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include #include - +#include #include #include #include "mp4item.h" diff --git a/taglib/mp4/mp4properties.cpp b/taglib/mp4/mp4properties.cpp index 3e4dcdfb..933180b1 100644 --- a/taglib/mp4/mp4properties.cpp +++ b/taglib/mp4/mp4properties.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include @@ -130,7 +128,7 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) d->bitsPerSample = data.toInt16BE(42); d->sampleRate = data.toUInt32BE(46); if(data.mid(56, 4) == "esds" && data[64] == 0x03) { - long pos = 65; + uint pos = 65; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index 8b3415cb..6c0174ca 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include #include @@ -114,9 +112,9 @@ MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, boo int i = 0; size_t pos = 0; while(pos < data.size()) { - int length = data.toUInt32BE(pos); - ByteVector name = data.mid(pos + 4, 4); - int flags = data.toUInt32BE(pos + 8); + const int length = data.toUInt32BE(pos); + const ByteVector name = data.mid(pos + 4, 4); + const int flags = data.toUInt32BE(pos + 8); if(freeForm && i < 2) { if(i == 0 && name != "mean") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); @@ -277,9 +275,9 @@ MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) ByteVector data = file->readBlock(atom->length - 8); size_t pos = 0; while(pos < data.size()) { - int length = data.toUInt32BE(pos); - ByteVector name = data.mid(pos + 4, 4); - int flags = data.toUInt32BE(pos + 8); + const int length = data.toUInt32BE(pos); + const ByteVector name = data.mid(pos + 4, 4); + const int flags = data.toUInt32BE(pos + 8); if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); break; @@ -575,7 +573,7 @@ MP4::Tag::updateOffsets(long delta, offset_t offset) } d->file->seek(atom->offset + 9); ByteVector data = d->file->readBlock(atom->length - 9); - unsigned int flags = data.toUInt24BE(0); + const uint flags = data.toUInt24BE(0); if(flags & 1) { long long o = data.toInt64BE(7); if(o > offset) { diff --git a/taglib/mpc/mpcproperties.cpp b/taglib/mpc/mpcproperties.cpp index 95cb5bf8..1422002b 100644 --- a/taglib/mpc/mpcproperties.cpp +++ b/taglib/mpc/mpcproperties.cpp @@ -293,7 +293,7 @@ void MPC::Properties::readSV7(const ByteVector &data) d->sampleFrames = d->totalFrames * 1152 - 576; } else { - uint headerData = data.toUInt32LE(0); + const uint headerData = data.toUInt32LE(0); d->bitrate = (headerData >> 23) & 0x01ff; d->version = (headerData >> 11) & 0x03ff; diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index af54ab36..60e0a248 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #if HAVE_ZLIB #include @@ -711,7 +709,7 @@ void Frame::Header::setData(const ByteVector &data, uint version) // iTunes writes v2.4 tags with v2.3-like frame sizes if(d->frameSize > 127) { if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) { - unsigned int uintSize = data.toUInt32BE(4); + const uint uintSize = data.toUInt32BE(4); if(isValidFrameID(data.mid(uintSize + 10, 4))) { d->frameSize = uintSize; } diff --git a/taglib/mpeg/id3v2/id3v2framefactory.cpp b/taglib/mpeg/id3v2/id3v2framefactory.cpp index 0ac17090..4dceb26a 100644 --- a/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ b/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include diff --git a/taglib/mpeg/mpegheader.cpp b/taglib/mpeg/mpegheader.cpp index e54f9b3d..348cb81d 100644 --- a/taglib/mpeg/mpegheader.cpp +++ b/taglib/mpeg/mpegheader.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - #include #include diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index b832a0d6..3b844771 100644 --- a/taglib/ogg/flac/oggflacfile.cpp +++ b/taglib/ogg/flac/oggflacfile.cpp @@ -251,7 +251,7 @@ void Ogg::FLAC::File::scan() return; } - d->streamInfoData = metadataHeader.mid(4,length); + d->streamInfoData = metadataHeader.mid(4, length); // Search through the remaining metadata diff --git a/taglib/ogg/opus/opusproperties.cpp b/taglib/ogg/opus/opusproperties.cpp index 8ec72438..ae350809 100644 --- a/taglib/ogg/opus/opusproperties.cpp +++ b/taglib/ogg/opus/opusproperties.cpp @@ -118,7 +118,7 @@ void Opus::Properties::read() ByteVector data = d->file->packet(0); // *Magic Signature* - int pos = 8; + uint pos = 8; // *Version* (8 bits, unsigned) d->opusVersion = uchar(data.at(pos)); @@ -129,7 +129,7 @@ void Opus::Properties::read() pos += 1; // *Pre-skip* (16 bits, unsigned, little endian) - ushort preSkip = data.toUInt16LE(pos); + const ushort preSkip = data.toUInt16LE(pos); pos += 2; // *Input Sample Rate* (32 bits, unsigned, little endian) diff --git a/taglib/ogg/vorbis/vorbisproperties.cpp b/taglib/ogg/vorbis/vorbisproperties.cpp index 47934e54..3b2afb46 100644 --- a/taglib/ogg/vorbis/vorbisproperties.cpp +++ b/taglib/ogg/vorbis/vorbisproperties.cpp @@ -142,7 +142,7 @@ void Ogg::Vorbis::Properties::read() ByteVector data = d->file->packet(0); - int pos = 0; + uint pos = 0; if(data.mid(pos, 7) != vorbisSetupHeaderID) { debug("Ogg::Vorbis::Properties::read() -- invalid Ogg::Vorbis identification header"); diff --git a/taglib/ogg/xiphcomment.cpp b/taglib/ogg/xiphcomment.cpp index 40b54d60..ecb40522 100644 --- a/taglib/ogg/xiphcomment.cpp +++ b/taglib/ogg/xiphcomment.cpp @@ -354,7 +354,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) // Next the number of fields in the comment vector. - uint commentFields = data.toUInt32LE(pos); + const uint commentFields = data.toUInt32LE(pos); pos += 4; if(commentFields > (data.size() - 8) / 4) { @@ -366,7 +366,7 @@ void Ogg::XiphComment::parse(const ByteVector &data) // Each comment field is in the format "KEY=value" in a UTF8 string and has // 4 bytes before the text starts that gives the length. - uint commentLength = data.toUInt32LE(pos); + const uint commentLength = data.toUInt32LE(pos); pos += 4; String comment = String(data.mid(pos, commentLength), String::UTF8); diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index af40cd04..20c810ec 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -48,7 +48,7 @@ static double ConvertFromIeeeExtended(const ByteVector &v, size_t offset) return 0.0; } - const unsigned char *bytes = reinterpret_cast(v.data() + offset); + const uchar *bytes = reinterpret_cast(v.data() + offset); double f; int expon; unsigned long hiMant, loMant; diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index 65bc00a8..86670c69 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -161,6 +161,11 @@ void RIFF::File::setChunkData(uint i, const ByteVector &data) d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding; } +void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data) +{ + setChunkData(name, data, false); +} + void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate) { if(d->chunks.size() == 0) { diff --git a/taglib/riff/rifffile.h b/taglib/riff/rifffile.h index 6e7dce3f..9197196d 100644 --- a/taglib/riff/rifffile.h +++ b/taglib/riff/rifffile.h @@ -102,17 +102,27 @@ namespace TagLib { */ void setChunkData(uint i, const ByteVector &data); + /*! + * Sets the data for the chunk \a name to \a data. If a chunk with the + * given name already exists it will be overwritten, otherwise it will be + * created after the existing chunks. + * + * \warning This will update the file immediately. + */ + void setChunkData(const ByteVector &name, const ByteVector &data); + /*! * Sets the data for the chunk \a name to \a data. If a chunk with the * given name already exists it will be overwritten, otherwise it will be * created after the existing chunks. * * \note If \a alwaysCreate is true, a new chunk is created regardless of - * existence of chunk \a name. It should be used for only "LIST" chunks. + * whether or not the chunk \a name exists. It should only be used for + * "LIST" chunks. * * \warning This will update the file immediately. */ - void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate = false); + void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate); /*! * Removes the specified chunk. diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index 11188541..d823b969 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler + copyright : (C) 2012 by Tsuda Kageyu email : wheeler@kde.org ***************************************************************************/ @@ -84,17 +84,18 @@ ByteVector RIFF::Info::StringHandler::render(const String &s) const RIFF::Info::Tag::Tag(const ByteVector &data) : TagLib::Tag() { - d = new TagPrivate; parse(data); } -RIFF::Info::Tag::Tag() : TagLib::Tag() +RIFF::Info::Tag::Tag() + : TagLib::Tag() + , d(new TagPrivate()) { - d = new TagPrivate; } RIFF::Info::Tag::~Tag() { + delete d; } String RIFF::Info::Tag::title() const @@ -245,7 +246,7 @@ void RIFF::Info::Tag::parse(const ByteVector &data) { size_t p = 4; while(p < data.size()) { - uint size = data.toUInt32LE(p + 4); + const uint size = data.toUInt32LE(p + 4); d->fieldListMap[data.mid(p, 4)] = TagPrivate::stringHandler->parse(data.mid(p + 8, size)); p += ((size + 1) & ~1) + 8; diff --git a/taglib/riff/wav/infotag.h b/taglib/riff/wav/infotag.h index 70933ea1..a812e87e 100644 --- a/taglib/riff/wav/infotag.h +++ b/taglib/riff/wav/infotag.h @@ -1,6 +1,6 @@ /*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org + copyright : (C) 2012 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** @@ -82,7 +82,7 @@ namespace TagLib { * This is the main class in the INFO tag implementation. RIFF INFO tag is a * metadata format found in WAV audio and AVI video files. Though it is a part * of Microsoft/IBM's RIFF specification, the author could not find the official - * documents about it. So, this implementation is refering to unofficial documents + * documents about it. So, this implementation is referring to unofficial documents * online and some applications' behaviors especially Windows Explorer. */ class TAGLIB_EXPORT Tag : public TagLib::Tag @@ -119,6 +119,7 @@ namespace TagLib { virtual void setTrack(uint i); virtual bool isEmpty() const; + /* * Gets the value of the field with the ID \a id. */ @@ -129,7 +130,7 @@ namespace TagLib { * If the field does not exist, it is created. * If \s is empty, the field is removed. * - * \note fieldId must be four-byte long pure ascii string. This function + * \note fieldId must be four-byte long pure ASCII string. This function * performs nothing if fieldId is invalid. */ void setFieldText(const ByteVector &id, const String &s); diff --git a/taglib/toolkit/taglib.h b/taglib/toolkit/taglib.h old mode 100755 new mode 100644 index f73eaed5..e3b770ad --- a/taglib/toolkit/taglib.h +++ b/taglib/toolkit/taglib.h @@ -52,31 +52,24 @@ # endif # define _FILE_OFFSET_BITS 64 # include - #endif // Check the widths of integral types. -#if UCHAR_MAX != 255U -# error TagLib assumes that char is 8-bit wide. +#if SIZEOF_SHORT != 2 +# error TagLib requires that short is 16-bit wide. #endif -#if USHRT_MAX != 65535U -# error TagLib assumes that short is 16-bit wide. +#if SIZEOF_INT != 4 +# error TagLib requires that int is 32-bit wide. #endif -#if UINT_MAX != 4294967295U -# error TagLib assumes that int is 32-bit wide. +#if SIZEOF_LONGLONG != 8 +# error TagLib requires that long long is 64-bit wide. #endif -#if !defined(ULLONG_MAX) && !defined(ULONGLONG_MAX) && !defined(ULONG_LONG_MAX) -# error TagLib assumes that long long is 64-bit wide. -#elif defined(ULLONG_MAX) && ULLONG_MAX != 18446744073709551615ULL -# error TagLib assumes that long long is 64-bit wide. -#elif defined(ULONGLONG_MAX) && ULONGLONG_MAX != 18446744073709551615ULL -# error TagLib assumes that long long is 64-bit wide. -#elif defined(ULONG_LONG_MAX) && ULONG_LONG_MAX != 18446744073709551615ULL -# error TagLib assumes that long long is 64-bit wide. +#if SIZEOF_WCHAR_T < 2 +# error TagLib requires that wchar_t is sufficient to store a UTF-16 char. #endif // Optimized byte swap functions. @@ -162,7 +155,11 @@ namespace TagLib { * Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3) * so I'm providing something here that should be constant. */ +#ifdef HAVE_STD_WSTRING + typedef std::wstring wstring; +#else typedef std::basic_string wstring; +#endif } /*! diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index bf10e2be..d1d714d6 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -24,9 +24,10 @@ ***************************************************************************/ #include +#include +#include #include #include -#include #include "tbytevector.h" @@ -493,11 +494,8 @@ const char *ByteVector::data() const ByteVector ByteVector::mid(size_t index, size_t length) const { - if(index > size()) - index = size(); - - if(length > size() - index) - length = size() - index; + index = std::min(index, size()); + length = std::min(length, size() - index); return ByteVector(*this, index, length); } @@ -793,7 +791,6 @@ long long ByteVector::toInt64BE(size_t offset) const return static_cast(toNumber(*this, offset)); } - const char &ByteVector::operator[](size_t index) const { return DATA(d)[d->offset + index]; diff --git a/taglib/toolkit/tbytevectorlist.cpp b/taglib/toolkit/tbytevectorlist.cpp index f4bd512b..505c3bf8 100644 --- a/taglib/toolkit/tbytevectorlist.cpp +++ b/taglib/toolkit/tbytevectorlist.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - #include "tbytevectorlist.h" using namespace TagLib; diff --git a/taglib/toolkit/tfilestream.cpp b/taglib/toolkit/tfilestream.cpp index f8180a21..06d04a34 100644 --- a/taglib/toolkit/tfilestream.cpp +++ b/taglib/toolkit/tfilestream.cpp @@ -40,48 +40,79 @@ using namespace TagLib; -namespace { +namespace +{ #ifdef _WIN32 - // For Windows + // Using Win32 native API instead of standard C file I/O to reduce the resource consumption. typedef FileName FileNameHandle; - // Using native file handles instead of file descriptors for reducing the resource consumption. - - const HANDLE InvalidFile = INVALID_HANDLE_VALUE; +# define INVALID_FILE INVALID_HANDLE_VALUE HANDLE openFile(const FileName &path, bool readOnly) { - DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); + const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); if(!path.wstr().empty()) return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - else + else if(!path.str().empty()) return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + else + return INVALID_FILE; } size_t fread(void *ptr, size_t size, size_t nmemb, HANDLE stream) { DWORD readLen; - ReadFile(stream, ptr, static_cast(size * nmemb), &readLen, NULL); - - return (readLen / size); + if(ReadFile(stream, ptr, size * nmemb, &readLen, NULL)) + return (readLen / size); + else + return 0; } size_t fwrite(const void *ptr, size_t size, size_t nmemb, HANDLE stream) { DWORD writtenLen; - WriteFile(stream, ptr, static_cast(size * nmemb), &writtenLen, NULL); - - return writtenLen; + if(WriteFile(stream, ptr, size * nmemb, &writtenLen, NULL)) + return (writtenLen / size); + else + return 0; } +# if _DEBUG + + // Convert a string in a local encoding into a UTF-16 string. + + // This function should only be used to generate an error message. + // In actual use, file names in local encodings are passed to CreateFileA() + // without any conversions. + + String fileNameToString(const FileName &name) + { + if(!name.wstr().empty()) { + return String(name.wstr()); + } + else if(!name.str().empty()) { + const int len = MultiByteToWideChar(CP_ACP, 0, name.str().c_str(), -1, NULL, 0); + if(len == 0) + return String::null; + + wstring wstr(len, L'\0'); + MultiByteToWideChar(CP_ACP, 0, name.str().c_str(), -1, &wstr[0], len); + + return String(wstr); + } + else { + return String::null; + } + } + +# endif + #else - // For non-Windows - - FILE *const InvalidFile = 0; +# define INVALID_FILE 0 struct FileNameHandle : public std::string { @@ -100,7 +131,7 @@ namespace { class FileStream::FileStreamPrivate { public: - FileStreamPrivate(FileName fileName, bool openReadOnly); + FileStreamPrivate(const FileName &fileName, bool openReadOnly); #ifdef _WIN32 @@ -128,8 +159,8 @@ public: #endif }; -FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName, bool openReadOnly) : - file(InvalidFile), +FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool openReadOnly) : + file(INVALID_FILE), name(fileName), readOnly(true), size(0) @@ -139,23 +170,22 @@ FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName, bool openRea if(!openReadOnly) file = openFile(name, false); - if(file != InvalidFile) + if(file != INVALID_FILE) readOnly = false; else file = openFile(name, true); - if(file == InvalidFile) { -#ifdef _WIN32 - String n; - if(!name.wstr().empty()) - n = name.wstr(); - else - n = name.str(); -#else - String n(name); -#endif // DEBUG + if(file == INVALID_FILE) + { +# ifdef _WIN32 - debug("Could not open file " + n); + debug("Could not open file " + fileNameToString(name)); + +# else + + debug("Could not open file " + String((const char *) name)); + +# endif } } @@ -164,20 +194,20 @@ FileStream::FileStreamPrivate::FileStreamPrivate(FileName fileName, bool openRea //////////////////////////////////////////////////////////////////////////////// FileStream::FileStream(FileName file, bool openReadOnly) + : d(new FileStreamPrivate(file, openReadOnly)) { - d = new FileStreamPrivate(file, openReadOnly); } FileStream::~FileStream() { #ifdef _WIN32 - if(d->file) + if(isOpen()) CloseHandle(d->file); #else - if(d->file) + if(isOpen()) fclose(d->file); #endif @@ -192,8 +222,8 @@ FileName FileStream::name() const ByteVector FileStream::readBlock(size_t length) { - if(!d->file) { - debug("FileStream::readBlock() -- Invalid File"); + if(!isOpen()) { + debug("File::readBlock() -- invalid file."); return ByteVector::null; } @@ -211,11 +241,13 @@ ByteVector FileStream::readBlock(size_t length) void FileStream::writeBlock(const ByteVector &data) { - if(!d->file) + if(!isOpen()) { + debug("File::writeBlock() -- invalid file."); return; + } - if(d->readOnly) { - debug("File::writeBlock() -- attempted to write to a file that is not writable"); + if(readOnly()) { + debug("File::writeBlock() -- read only file."); return; } @@ -224,8 +256,15 @@ void FileStream::writeBlock(const ByteVector &data) void FileStream::insert(const ByteVector &data, offset_t start, size_t replace) { - if(!d->file) + if(!isOpen()) { + debug("File::insert() -- invalid file."); return; + } + + if(readOnly()) { + debug("File::insert() -- read only file."); + return; + } if(data.size() == replace) { seek(start); @@ -325,8 +364,10 @@ void FileStream::insert(const ByteVector &data, offset_t start, size_t replace) void FileStream::removeBlock(offset_t start, size_t length) { - if(!d->file) + if(!isOpen()) { + debug("File::removeBlock() -- invalid file."); return; + } size_t bufferLength = FileStreamPrivate::bufferSize; @@ -362,13 +403,13 @@ bool FileStream::readOnly() const bool FileStream::isOpen() const { - return (d->file != NULL); + return (d->file != INVALID_FILE); } void FileStream::seek(offset_t offset, Position p) { - if(!d->file) { - debug("FileStream::seek() -- trying to seek in a file that isn't opened."); + if(!isOpen()) { + debug("File::seek() -- invalid file."); return; } @@ -390,9 +431,10 @@ void FileStream::seek(offset_t offset, Position p) return; } - LARGE_INTEGER largeOffset = {}; - largeOffset.QuadPart = offset; - SetFilePointerEx(d->file, largeOffset, nullptr, whence); + SetFilePointer(d->file, offset, NULL, whence); + if(GetLastError() != NO_ERROR) { + debug("File::seek() -- Failed to set the file size."); + } #else @@ -442,12 +484,14 @@ offset_t FileStream::tell() const { #ifdef _WIN32 - const LARGE_INTEGER largeOffset = {}; - LARGE_INTEGER newPointer; - - SetFilePointerEx(d->file, largeOffset, &newPointer, FILE_CURRENT); - - return newPointer.QuadPart; + const DWORD position = SetFilePointer(d->file, 0, NULL, FILE_CURRENT); + if(GetLastError() == NO_ERROR) { + return static_cast(position); + } + else { + debug("File::tell() -- Failed to get the file pointer."); + return 0; + } #else @@ -466,13 +510,30 @@ offset_t FileStream::tell() const offset_t FileStream::length() { + if(!isOpen()) { + debug("File::length() -- invalid file."); + return 0; + } + // Do some caching in case we do multiple calls. if(d->size > 0) return d->size; - if(!d->file) +#ifdef _WIN32 + + const DWORD fileSize = GetFileSize(d->file, NULL); + if(GetLastError() == NO_ERROR) { + d->size = static_cast(fileSize); + return d->size; + } + else { + debug("File::length() -- Failed to get the file size."); + d->size = 0; return 0; + } + +#else const offset_t currentPosition = tell(); @@ -483,6 +544,8 @@ offset_t FileStream::length() d->size = endPosition; return endPosition; + +#endif } //////////////////////////////////////////////////////////////////////////////// @@ -493,14 +556,15 @@ void FileStream::truncate(offset_t length) { #ifdef _WIN32 - const offset_t currentPosition = tell(); + const offset_t currentPos = tell(); seek(length); - BOOL set = SetEndOfFile(d->file); - if(!set) { - debug("FileStream::truncate() -- Coundn't truncate the file."); + SetEndOfFile(d->file); + if(GetLastError() != NO_ERROR) { + debug("File::truncate() -- Failed to truncate the file."); } - seek(currentPosition); + + seek(currentPos); #else diff --git a/taglib/toolkit/tiostream.cpp b/taglib/toolkit/tiostream.cpp index e7b60dd7..55262954 100644 --- a/taglib/toolkit/tiostream.cpp +++ b/taglib/toolkit/tiostream.cpp @@ -27,6 +27,87 @@ using namespace TagLib; +#ifdef _WIN32 + +// MSVC 2008 or later can't produce the binary for Win9x. +#if !defined(_MSC_VER) || (_MSC_VER < 1500) + +namespace +{ + + // Determines whether or not the running system is WinNT. + // In other words, whether the system supports Unicode. + + bool isWinNT() + { + OSVERSIONINFOA ver = {}; + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if(GetVersionExA(&ver)) { + return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT); + } + else { + return false; + } + } + + const bool IsWinNT = isWinNT(); + + // Converts a UTF-16 string into a local encoding. + + std::string unicodeToAnsi(const std::wstring &wstr) + { + const int len = WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, NULL, 0, NULL, NULL); + if(len == 0) + return std::string(); + + std::string str(len, '\0'); + WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, &str[0], len, NULL, NULL); + + return str; + } +} + +// If WinNT, stores a Unicode string into m_wname directly. +// If Win9x, converts and stores it into m_name to avoid calling Unicode version functions. + +FileName::FileName(const wchar_t *name) + : m_wname(IsWinNT ? name : L"") + , m_name(IsWinNT ? "" : unicodeToAnsi(name)) +{ +} + +#else + +FileName::FileName(const wchar_t *name) + : m_wname(name) +{ +} + +#endif + +FileName::FileName(const char *name) + : m_name(name) +{ +} + +FileName::FileName(const FileName &name) + : m_wname(name.m_wname) + , m_name(name.m_name) +{ +} + +const std::wstring &FileName::wstr() const +{ + return m_wname; +} + +const std::string &FileName::str() const +{ + return m_name; +} + +#endif + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index ff223468..6a439cba 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -39,14 +39,16 @@ namespace TagLib { class TAGLIB_EXPORT FileName { public: - FileName(const wchar_t *name) : m_wname(name) {} - FileName(const char *name) : m_name(name) {} + FileName(const wchar_t *name); + FileName(const char *name); - const std::wstring &wstr() const { return m_wname; } - const std::string &str() const { return m_name; } + FileName(const FileName &name); + + const std::wstring &wstr() const; + const std::string &str() const; private: - const std::string m_name; + const std::string m_name; const std::wstring m_wname; }; #else diff --git a/taglib/toolkit/tlist.tcc b/taglib/toolkit/tlist.tcc index fb4d01c0..6a2baf2e 100644 --- a/taglib/toolkit/tlist.tcc +++ b/taglib/toolkit/tlist.tcc @@ -23,10 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - +#include #include namespace TagLib { diff --git a/taglib/toolkit/tmap.tcc b/taglib/toolkit/tmap.tcc index 3066144e..4c224b61 100644 --- a/taglib/toolkit/tmap.tcc +++ b/taglib/toolkit/tmap.tcc @@ -23,9 +23,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif +#include namespace TagLib { diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h index 54ecf307..56bd9f15 100644 --- a/taglib/toolkit/trefcountptr.h +++ b/taglib/toolkit/trefcountptr.h @@ -26,9 +26,7 @@ #ifndef TAGLIB_REFCOUNTPTR_H #define TAGLIB_REFCOUNTPTR_H -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include "config.h" #if defined(HAVE_STD_SHARED_PTR) # include diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 1637f038..63a7970a 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -25,21 +25,20 @@ // This class assumes that std::basic_string has a contiguous and null-terminated buffer. -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #include "tstring.h" #include "tdebug.h" #include "tstringlist.h" #include -#ifdef HAVE_CODECVT +// x86 CPUs are alignment-tolerant or allow pointer casts from smaller types to larger types. +#if defined(__i386__) || defined(_M_IX86) || defined(__amd64) || defined(__amd64__) \ + || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) +# define TAGLIB_ALIGNMENT_TOLERANT 1 +#endif + +#ifdef HAVE_STD_CODECVT # include - namespace { - typedef std::codecvt_utf8_utf16 utf8_utf16_t; - } #else # include "unicode.h" #endif @@ -63,6 +62,98 @@ namespace { return (c1 << 8) | c2; } + + void UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) + { +#ifdef HAVE_STD_CODECVT + + typedef std::codecvt_utf8_utf16 utf8_utf16_t; + + using namespace TagLib; + + const wchar_t *srcBegin = src; + const wchar_t *srcEnd = srcBegin + srcLength; + + char *dstBegin = dst; + char *dstEnd = dstBegin + dstLength; + + std::mbstate_t st; + const wchar_t *source; + char *target; + memset(&st, 0, sizeof(st)); + std::codecvt_base::result result = utf8_utf16_t().out( + st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); + + if(result != utf8_utf16_t::ok) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#else + + using namespace Unicode; + using namespace TagLib; + + const Unicode::UTF16 *srcBegin = src; + const Unicode::UTF16 *srcEnd = srcBegin + srcLength; + + Unicode::UTF8 *dstBegin = reinterpret_cast(dst); + Unicode::UTF8 *dstEnd = dstBegin + dstLength; + + Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( + &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::to8Bit() - Unicode conversion error."); + } + +#endif + } + + void UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) + { +#ifdef HAVE_STD_CODECVT + + typedef std::codecvt_utf8_utf16 utf8_utf16_t; + + using namespace TagLib; + + const char *srcBegin = src; + const char *srcEnd = srcBegin + srcLength; + + wchar_t *dstBegin = dst; + wchar_t *dstEnd = dstBegin + dstLength; + + std::mbstate_t st; + const char *source; + wchar_t *target; + memset(&st, 0, sizeof(st)); + std::codecvt_base::result result = utf8_utf16_t().in( + st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); + + if(result != utf8_utf16_t::ok) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#else + + using namespace Unicode; + using namespace TagLib; + + const Unicode::UTF8 *srcBegin = reinterpret_cast(src); + const Unicode::UTF8 *srcEnd = srcBegin + srcLength; + + Unicode::UTF16 *dstBegin = dst; + Unicode::UTF16 *dstEnd = dstBegin + dstLength; + + Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( + &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); + + if(result != Unicode::conversionOK) { + debug("String::copyFromUTF8() - Unicode conversion error."); + } + +#endif + } } namespace TagLib { @@ -87,6 +178,11 @@ public: } #endif + + StringPrivate(size_t n, wchar_t c) + : data(n, c) + { + } /*! * Stores string in UTF-16. The byte order depends on the CPU endian. @@ -180,14 +276,10 @@ String::String(wchar_t c, Type t) } String::String(char c, Type t) - : d(new StringPrivate()) + : d(new StringPrivate(1, static_cast(c))) { - if(t == Latin1 || t == UTF8) { - d->data.resize(1); - d->data[0] = static_cast(c); - } - else { - debug("String::String() -- A char should not contain UTF16."); + if(t != Latin1 && t != UTF8) { + debug("String::String() -- A char should not contain UTF16."); } } @@ -227,34 +319,7 @@ std::string String::to8Bit(bool unicode) const else { s.resize(d->data.size() * 4 + 1); -#ifdef HAVE_CODECVT - - std::mbstate_t st = 0; - const wchar_t *source; - char *target; - std::codecvt_base::result result = utf8_utf16_t().out( - st, &d->data[0], &d->data[d->data.size()], source, &s[0], &s[s.size()], target); - - if(result != utf8_utf16_t::ok) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#else - - const Unicode::UTF16 *source = &d->data[0]; - Unicode::UTF8 *target = reinterpret_cast(&s[0]); - - Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( - &source, source + d->data.size(), - &target, target + s.size(), - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::to8Bit() - Unicode conversion error."); - } - -#endif - + UTF16toUTF8(&d->data[0], d->data.size(), &s[0], s.size()); s.resize(::strlen(s.c_str())); } @@ -398,34 +463,7 @@ ByteVector String::data(Type t) const { ByteVector v(size() * 4 + 1, 0); -#ifdef HAVE_CODECVT - - std::mbstate_t st = 0; - const wchar_t *source; - char *target; - std::codecvt_base::result result = utf8_utf16_t().out( - st, &d->data[0], &d->data[d->data.size()], source, v.data(), v.data() + v.size(), target); - - if(result != utf8_utf16_t::ok) { - debug("String::data() - Unicode conversion error."); - } - -#else - - const Unicode::UTF16 *source = &d->data[0]; - Unicode::UTF8 *target = reinterpret_cast(v.data()); - - Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( - &source, source + d->data.size(), - &target, target + v.size(), - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::data() - Unicode conversion error."); - } - -#endif - + UTF16toUTF8(&d->data[0], d->data.size(), v.data(), v.size()); v.resize(::strlen(v.data())); return v; @@ -703,19 +741,13 @@ String &String::operator=(const wchar_t *s) String &String::operator=(char c) { - d.reset(new StringPrivate()); - d->data.resize(1); - d->data[0] = static_cast(c); - + d.reset(new StringPrivate(1, static_cast(c))); return *this; } String &String::operator=(wchar_t c) { - d.reset(new StringPrivate()); - d->data.resize(1); - d->data[0] = c; - + d.reset(new StringPrivate(1, c)); return *this; } @@ -769,34 +801,7 @@ void String::copyFromUTF8(const char *s, size_t length) { d->data.resize(length); -#ifdef HAVE_CODECVT - - std::mbstate_t st = 0; - const char *source; - wchar_t *target; - std::codecvt_base::result result = utf8_utf16_t().in( - st, s, s + length, source, &d->data[0], &d->data[d->data.size()], target); - - if(result != utf8_utf16_t::ok) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#else - - const Unicode::UTF8 *source = reinterpret_cast(s); - Unicode::UTF16 *target = &d->data[0]; - - Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( - &source, source + length, - &target, target + length, - Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#endif - + UTF8toUTF16(s, length, &d->data[0], d->data.size()); d->data.resize(::wcslen(d->data.c_str())); } @@ -824,20 +829,32 @@ 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] = byteSwap(static_cast(s[i])); } } -template -void String::internalCopyFromUTF16(const char *s, size_t length, Type t) +void String::copyFromUTF16(const char *s, size_t length, Type t) { - // Non specialized version. Used where sizeof(wchar_t) != 2. +#if SIZEOF_WCHAR_T == 2 && defined(TAGLIB_ALIGNMENT_TOLERANT) + + copyFromUTF16(reinterpret_cast(s), length / 2, t); + +#else bool swap; if(t == UTF16) { - if(length >= 2 && *reinterpret_cast(s) == 0xfeff) + if(length < 2) { + debug("String::copyFromUTF16() - Invalid UTF16 string."); + return; + } + + // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. + ushort bom; + ::memcpy(&bom, s, 2); + + if(bom == 0xfeff) swap = false; // Same as CPU endian. No need to swap bytes. - else if(length >= 2 && *reinterpret_cast(s) == 0xfffe) + else if(bom == 0xfffe) swap = true; // Not same as CPU endian. Need to swap bytes. else { debug("String::copyFromUTF16() - Invalid UTF16 string."); @@ -855,19 +872,8 @@ void String::internalCopyFromUTF16(const char *s, size_t length, Type t) d->data[i] = swap ? combine(*s, *(s + 1)) : combine(*(s + 1), *s); s += 2; } -} -template <> -void String::internalCopyFromUTF16<2>(const char *s, size_t length, Type t) -{ - // Specialized version for where sizeof(wchar_t) == 2. - - copyFromUTF16(reinterpret_cast(s), length / 2, t); -} - -void String::copyFromUTF16(const char *s, size_t length, Type t) -{ - internalCopyFromUTF16(s, length, t); +#endif } #ifdef TAGLIB_LITTLE_ENDIAN diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index bfa35459..01398fc9 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -511,9 +511,6 @@ namespace TagLib { * \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. diff --git a/taglib/toolkit/tstringlist.cpp b/taglib/toolkit/tstringlist.cpp index 4c90fe9b..49650f49 100644 --- a/taglib/toolkit/tstringlist.cpp +++ b/taglib/toolkit/tstringlist.cpp @@ -23,10 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include -#endif - #include "tstringlist.h" using namespace TagLib; diff --git a/tests/test_string.cpp b/tests/test_string.cpp index 2b7a9323..ae4ccedf 100644 --- a/tests/test_string.cpp +++ b/tests/test_string.cpp @@ -62,6 +62,13 @@ public: String latin = "Jos\xe9 Carlos"; CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0); + String c; + c = "1"; + CPPUNIT_ASSERT(c == L"1"); + + c = L'\u4E00'; + CPPUNIT_ASSERT(c == L"\u4E00"); + String unicode2(unicode.to8Bit(true), String::UTF8); CPPUNIT_ASSERT(unicode == unicode2);