Merge branch 'master' into merge-master

Conflicts:
	ConfigureChecks.cmake
	config-taglib.h.cmake
	taglib/CMakeLists.txt
	taglib/ape/apefooter.cpp
	taglib/ape/apeitem.cpp
	taglib/ape/apeproperties.cpp
	taglib/asf/asfattribute.cpp
	taglib/asf/asffile.cpp
	taglib/asf/asfpicture.cpp
	taglib/fileref.cpp
	taglib/flac/flacfile.cpp
	taglib/flac/flacpicture.cpp
	taglib/flac/flacproperties.cpp
	taglib/mp4/mp4atom.cpp
	taglib/mp4/mp4coverart.cpp
	taglib/mp4/mp4item.cpp
	taglib/mp4/mp4properties.cpp
	taglib/mp4/mp4tag.cpp
	taglib/mpc/mpcproperties.cpp
	taglib/mpeg/id3v2/frames/popularimeterframe.cpp
	taglib/mpeg/id3v2/frames/relativevolumeframe.cpp
	taglib/mpeg/id3v2/id3v2frame.cpp
	taglib/mpeg/id3v2/id3v2synchdata.cpp
	taglib/mpeg/xingheader.cpp
	taglib/ogg/flac/oggflacfile.cpp
	taglib/ogg/oggpageheader.cpp
	taglib/ogg/opus/opusproperties.cpp
	taglib/ogg/speex/speexproperties.cpp
	taglib/ogg/vorbis/vorbisproperties.cpp
	taglib/ogg/xiphcomment.cpp
	taglib/riff/aiff/aiffproperties.cpp
	taglib/riff/wav/infotag.cpp
	taglib/riff/wav/wavproperties.cpp
	taglib/toolkit/taglib.h
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tbytevector.h
	taglib/toolkit/tfilestream.cpp
	taglib/toolkit/tiostream.h
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tstringhandler.cpp
	taglib/trueaudio/trueaudioproperties.cpp
	taglib/wavpack/wavpackproperties.cpp
This commit is contained in:
Tsuda Kageyu 2013-05-01 20:06:55 +09:00
commit 36512745cf
47 changed files with 486 additions and 362 deletions

View File

@ -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

View File

@ -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 <string>
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 <codecvt>
int main() { std::codecvt_utf8_utf16<wchar_t> x; return 0; }
" HAVE_CODECVT)
#include <codecvt>
int main() {
std::codecvt_utf8_utf16<wchar_t> 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()

View File

@ -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 <codecvt> 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@"

View File

@ -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<int>(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);

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "asfattribute.h"

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tbytevectorlist.h>
#include <tpropertymap.h>

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#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);

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "config.h"
#include <tdebug.h>
#include <tstring.h>

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "config.h"
#include <tpropertymap.h>
#include "asftag.h"

View File

@ -27,13 +27,11 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
#ifdef _WIN32
# include <Shlwapi.h>
#endif
#endif
#include <tfile.h>
#include <tstring.h>
@ -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'.')

View File

@ -32,6 +32,10 @@
#include "taglib_export.h"
#include "audioproperties.h"
#if _WIN32
# pragma comment(lib, "shlwapi.lib")
#endif
namespace TagLib {
class Tag;

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "flacmetadatablock.h"

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#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.");

View File

@ -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;

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include <tstring.h>

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#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) {

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "mp4coverart.h"

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#include <tpropertymap.h>

View File

@ -23,13 +23,8 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <cstdarg>
#include <cstdio>
#include <cstdarg>
#include <taglib.h>
#include <tdebug.h>
#include "mp4item.h"

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "config.h"
#include <tdebug.h>
#include <tstring.h>
@ -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;
}

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "config.h"
#include <tdebug.h>
#include <tstring.h>
@ -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) {

View File

@ -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;

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "config.h"
#if HAVE_ZLIB
#include <zlib.h>
@ -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;
}

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "config.h"
#include <tdebug.h>

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <bitset>
#include <tbytevector.h>

View File

@ -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

View File

@ -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)

View File

@ -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");

View File

@ -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);

View File

@ -48,7 +48,7 @@ static double ConvertFromIeeeExtended(const ByteVector &v, size_t offset)
return 0.0;
}
const unsigned char *bytes = reinterpret_cast<const unsigned char*>(v.data() + offset);
const uchar *bytes = reinterpret_cast<const uchar*>(v.data() + offset);
double f;
int expon;
unsigned long hiMant, loMant;

View File

@ -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) {

View File

@ -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.

View File

@ -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;

View File

@ -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);

27
taglib/toolkit/taglib.h Executable file → Normal file
View File

@ -52,31 +52,24 @@
# endif
# define _FILE_OFFSET_BITS 64
# include <sys/types.h>
#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<wchar> wstring;
#endif
}
/*!

View File

@ -24,9 +24,10 @@
***************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <tstring.h>
#include <tdebug.h>
#include <string.h>
#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<long long>(toNumber<ulonglong, 8, BigEndian>(*this, offset));
}
const char &ByteVector::operator[](size_t index) const
{
return DATA(d)[d->offset + index];

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "tbytevectorlist.h"
using namespace TagLib;

View File

@ -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<DWORD>(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<DWORD>(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<long>(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<ulong>(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

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -23,10 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
#include <algorithm>
namespace TagLib {

View File

@ -23,9 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
namespace TagLib {

View File

@ -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 <memory>

View File

@ -25,21 +25,20 @@
// This class assumes that std::basic_string<T> 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 <string.h>
#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 <codecvt>
namespace {
typedef std::codecvt_utf8_utf16<wchar_t> 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<wchar_t> 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<Unicode::UTF8*>(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<wchar_t> 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<const Unicode::UTF8*>(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<uchar>(c)))
{
if(t == Latin1 || t == UTF8) {
d->data.resize(1);
d->data[0] = static_cast<uchar>(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<Unicode::UTF8*>(&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<Unicode::UTF8*>(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<uchar>(c);
d.reset(new StringPrivate(1, static_cast<uchar>(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<const Unicode::UTF8 *>(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<unsigned short>(s[i]));
d->data[i] = byteSwap(static_cast<ushort>(s[i]));
}
}
template <size_t sizeOfWcharT>
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<const wchar_t*>(s), length / 2, t);
#else
bool swap;
if(t == UTF16) {
if(length >= 2 && *reinterpret_cast<const TagLib::ushort*>(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<const TagLib::ushort*>(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<const wchar_t*>(s), length / 2, t);
}
void String::copyFromUTF16(const char *s, size_t length, Type t)
{
internalCopyFromUTF16<sizeof(wchar_t)>(s, length, t);
#endif
}
#ifdef TAGLIB_LITTLE_ENDIAN

View File

@ -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 <size_t sizeOfWcharT>
void internalCopyFromUTF16(const char *s, size_t length, Type t);
/*!
* Indicates which byte order of UTF-16 is used to store strings internally.

View File

@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "tstringlist.h"
using namespace TagLib;

View File

@ -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);