Merge branch 'master' into merge-master-to-taglib2

# Conflicts:
#	ConfigureChecks.cmake
#	taglib/CMakeLists.txt
#	taglib/asf/asfattribute.cpp
#	taglib/it/itproperties.cpp
#	taglib/mod/modproperties.cpp
#	taglib/mpeg/mpegfile.cpp
#	taglib/mpeg/mpegproperties.cpp
#	taglib/ogg/flac/oggflacfile.cpp
#	taglib/s3m/s3mproperties.cpp
#	taglib/tagunion.cpp
#	taglib/toolkit/tfile.cpp
#	taglib/toolkit/trefcounter.h
#	taglib/toolkit/tstring.cpp
#	taglib/xm/xmproperties.cpp
#	tests/test_mpeg.cpp
This commit is contained in:
Tsuda Kageyu
2017-02-21 10:18:03 +09:00
70 changed files with 1180 additions and 1052 deletions

View File

@@ -15,6 +15,7 @@ addons:
packages:
- libcppunit-dev
- zlib1g-dev
- libboost-dev
matrix:
exclude:

View File

@@ -57,7 +57,7 @@ endif()
check_cxx_source_compiles("
#include <atomic>
int main() {
std::atomic_int x;
std::atomic_int x(1);
++x;
--x;
return 0;
@@ -137,69 +137,57 @@ endif()
# Determine which kind of byte swap functions your compiler supports.
check_cxx_source_compiles("
#include <boost/endian/conversion.hpp>
int main() {
boost::endian::endian_reverse(static_cast<uint16_t>(1));
boost::endian::endian_reverse(static_cast<uint32_t>(1));
boost::endian::endian_reverse(static_cast<uint64_t>(1));
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
return 0;
}
" HAVE_BOOST_BYTESWAP)
" HAVE_GCC_BYTESWAP)
if(NOT HAVE_BOOST_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
int main() {
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
return 0;
}
" HAVE_GCC_BYTESWAP)
" HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
#include <stdlib.h>
int main() {
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
return 0;
}
" HAVE_GLIBC_BYTESWAP)
" HAVE_MSC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
check_cxx_source_compiles("
#include <stdlib.h>
#include <libkern/OSByteOrder.h>
int main() {
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(0);
return 0;
}
" HAVE_MSC_BYTESWAP)
" HAVE_MAC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
if(NOT HAVE_MAC_BYTESWAP)
check_cxx_source_compiles("
#include <libkern/OSByteOrder.h>
#include <sys/endian.h>
int main() {
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(0);
swap16(0);
swap32(0);
swap64(0);
return 0;
}
" HAVE_MAC_BYTESWAP)
if(NOT HAVE_MAC_BYTESWAP)
check_cxx_source_compiles("
#include <sys/endian.h>
int main() {
swap16(0);
swap32(0);
swap64(0);
return 0;
}
" HAVE_OPENBSD_BYTESWAP)
endif()
" HAVE_OPENBSD_BYTESWAP)
endif()
endif()
endif()

3
NEWS
View File

@@ -4,9 +4,10 @@
* Added support for classical music tags of iTunes 12.5.
* Dropped support for Windows 9x and NT 4.0 or older.
* Fixed reading MP4 atoms with zero length.
* Fixed handling of redundant UTF-8 sequences in Win32.
* Fixed handling of lowercase field names in Vorbis Comments.
* Fixed possible file corruptions when saving Ogg files.
* Fixed reading FLAC files with zero-sized seektables.
* Better handling of invalid UTF-8 sequences.
* Several smaller bug fixes and performance improvements.
TagLib 1.11.1 (Oct 24, 2016)

View File

@@ -9,7 +9,6 @@
#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
/* Defined if your compiler supports some byte swap functions */
#cmakedefine HAVE_BOOST_BYTESWAP 1
#cmakedefine HAVE_GCC_BYTESWAP 1
#cmakedefine HAVE_GLIBC_BYTESWAP 1
#cmakedefine HAVE_MSC_BYTESWAP 1

View File

@@ -344,12 +344,6 @@ set(toolkit_SRCS
toolkit/tzlib.cpp
)
if(NOT WIN32)
set(unicode_SRCS
toolkit/unicode.cpp
)
endif()
if(HAVE_ZLIB_SOURCE)
set(zlib_SRCS
${ZLIB_SOURCE}/adler32.c
@@ -367,7 +361,7 @@ set(tag_LIB_SRCS
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${ebml_SRCS} ${matroska_SRCS} ${dsf_SRCS}
${unicode_SRCS} ${zlib_SRCS}
${zlib_SRCS}
tag.cpp
tagunion.cpp
fileref.cpp

View File

@@ -63,8 +63,9 @@ namespace
return false;
}
const String upperKey = String(key).upper();
for(size_t i = 0; invalidKeys[i] != 0; ++i) {
if(String(key).upper() == invalidKeys[i])
if(upperKey == invalidKeys[i])
return false;
}

View File

@@ -1,4 +1,4 @@
/**************************************************************************
/**************************************************************************
copyright : (C) 2005-2007 by Lukáš Lalinský
email : lalinsky@gmail.com
**************************************************************************/
@@ -37,16 +37,16 @@ namespace
{
struct AttributeData
{
AttributeData() :
numericValue(0),
stream(0),
language(0) {}
ASF::Attribute::AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
ASF::Picture pictureValue;
union {
unsigned int intValue;
unsigned short shortValue;
unsigned long long longLongValue;
bool boolValue;
};
unsigned long long numericValue;
int stream;
int language;
};
@@ -59,8 +59,6 @@ public:
data(new AttributeData())
{
data->pictureValue = ASF::Picture::fromInvalid();
data->stream = 0;
data->language = 0;
}
SHARED_PTR<AttributeData> data;
@@ -106,33 +104,28 @@ ASF::Attribute::Attribute(unsigned int value) :
d(new AttributePrivate())
{
d->data->type = DWordType;
d->data->intValue = value;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(unsigned long long value) :
d(new AttributePrivate())
{
d->data->type = QWordType;
d->data->longLongValue = value;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(unsigned short value) :
d(new AttributePrivate())
{
d->data->type = WordType;
d->data->shortValue = value;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(bool value) :
d(new AttributePrivate())
{
d->data->type = BoolType;
d->data->boolValue = value;
}
ASF::Attribute::~Attribute()
{
delete d;
d->data->numericValue = value;
}
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
@@ -148,6 +141,11 @@ void ASF::Attribute::swap(Attribute &other)
swap(d, other.d);
}
ASF::Attribute::~Attribute()
{
delete d;
}
ASF::Attribute::AttributeTypes ASF::Attribute::type() const
{
return d->data->type;
@@ -168,22 +166,22 @@ ByteVector ASF::Attribute::toByteVector() const
unsigned short ASF::Attribute::toBool() const
{
return d->data->shortValue;
return d->data->numericValue ? 1 : 0;
}
unsigned short ASF::Attribute::toUShort() const
{
return d->data->shortValue;
return static_cast<unsigned short>(d->data->numericValue);
}
unsigned int ASF::Attribute::toUInt() const
{
return d->data->intValue;
return static_cast<unsigned int>(d->data->numericValue);
}
unsigned long long ASF::Attribute::toULongLong() const
{
return d->data->longLongValue;
return static_cast<unsigned long long>(d->data->numericValue);
}
ASF::Picture ASF::Attribute::toPicture() const
@@ -223,24 +221,24 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
switch(d->data->type) {
case WordType:
d->data->shortValue = readWORD(&f);
d->data->numericValue = readWORD(&f);
break;
case BoolType:
if(kind == 0) {
d->data->boolValue = (readDWORD(&f) == 1);
d->data->numericValue = (readDWORD(&f) != 0);
}
else {
d->data->boolValue = (readWORD(&f) == 1);
d->data->numericValue = (readWORD(&f) != 0);
}
break;
case DWordType:
d->data->intValue = readDWORD(&f);
d->data->numericValue = readDWORD(&f);
break;
case QWordType:
d->data->longLongValue = readQWORD(&f);
d->data->numericValue = readQWORD(&f);
break;
case UnicodeType:
@@ -291,24 +289,24 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
switch (d->data->type) {
case WordType:
data.append(ByteVector::fromUInt16LE(d->data->shortValue));
data.append(ByteVector::fromUInt16LE(toUShort()));
break;
case BoolType:
if(kind == 0) {
data.append(ByteVector::fromUInt32LE(d->data->boolValue ? 1 : 0));
data.append(ByteVector::fromUInt32LE(toBool()));
}
else {
data.append(ByteVector::fromUInt16LE(d->data->boolValue ? 1 : 0));
data.append(ByteVector::fromUInt16LE(toBool()));
}
break;
case DWordType:
data.append(ByteVector::fromUInt32LE(d->data->intValue));
data.append(ByteVector::fromUInt32LE(toUInt()));
break;
case QWordType:
data.append(ByteVector::fromUInt64LE(d->data->longLongValue));
data.append(ByteVector::fromUInt64LE(toULongLong()));
break;
case UnicodeType:

View File

@@ -40,10 +40,10 @@ public:
AttributeListMap attributeListMap;
};
ASF::Tag::Tag()
: TagLib::Tag()
ASF::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
d = new TagPrivate;
}
ASF::Tag::~Tag()

View File

@@ -63,11 +63,7 @@ namespace
// Templatized internal functions. T should be String or IOStream*.
template <typename T>
FileName toFileName(T arg)
{
debug("FileRef::toFileName<T>(): This version should never be called.");
return FileName(L"");
}
FileName toFileName(T arg);
template <>
FileName toFileName<IOStream *>(IOStream *arg)
@@ -83,11 +79,7 @@ namespace
template <typename T>
File *resolveFileType(T arg, bool readProperties,
AudioProperties::ReadStyle style)
{
debug("FileRef::resolveFileType<T>(): This version should never be called.");
return 0;
}
AudioProperties::ReadStyle style);
template <>
File *resolveFileType<IOStream *>(IOStream *arg, bool readProperties,

View File

@@ -183,7 +183,6 @@ bool FLAC::File::save()
}
// Compute the amount of padding, and append that to data.
// TODO: Should be calculated in offset_t in taglib2.
long long originalLength = d->streamStart - d->flacStart;
long long paddingLength = originalLength - data.size() - 4;
@@ -476,7 +475,9 @@ void FLAC::File::scan()
return;
}
if(blockLength == 0 && blockType != MetadataBlock::Padding) {
if(blockLength == 0
&& blockType != MetadataBlock::Padding && blockType != MetadataBlock::SeekTable)
{
debug("FLAC::File::scan() -- Zero-sized metadata block found");
setValid(false);
return;

View File

@@ -50,14 +50,14 @@ public:
ByteVector data;
};
FLAC::Picture::Picture()
FLAC::Picture::Picture() :
d(new PicturePrivate())
{
d = new PicturePrivate;
}
FLAC::Picture::Picture(const ByteVector &data)
FLAC::Picture::Picture(const ByteVector &data) :
d(new PicturePrivate())
{
d = new PicturePrivate;
parse(data);
}

View File

@@ -39,11 +39,10 @@ public:
ByteVector data;
};
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data)
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) :
d(new UnknownMetadataBlockPrivate())
{
d = new UnknownMetadataBlockPrivate;
d->code = code;
//debug(String(data.toHex()));
d->data = data;
}

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright :(C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
@@ -48,7 +48,7 @@ public:
Mod::AudioProperties::AudioProperties(AudioProperties::ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate)
d(new PropertiesPrivate())
{
}

View File

@@ -44,9 +44,10 @@ public:
String trackerName;
};
Mod::Tag::Tag() : TagLib::Tag()
Mod::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
d = new TagPrivate;
}
Mod::Tag::~Tag()

View File

@@ -48,14 +48,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC")
AttachedPictureFrame::AttachedPictureFrame() :
Frame("APIC"),
d(new AttachedPictureFramePrivate())
{
d = new AttachedPictureFramePrivate;
}
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data)
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) :
Frame(data),
d(new AttachedPictureFramePrivate())
{
d = new AttachedPictureFramePrivate;
setData(data);
}
@@ -169,9 +171,10 @@ ByteVector AttachedPictureFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h)
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new AttachedPictureFramePrivate())
{
d = new AttachedPictureFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -61,9 +61,9 @@ public:
////////////////////////////////////////////////////////////////////////////////
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
ID3v2::Frame(data),
d(new ChapterFramePrivate())
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
@@ -72,10 +72,9 @@ ChapterFrame::ChapterFrame(const ByteVector &elementID,
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames) :
ID3v2::Frame("CHAP")
ID3v2::Frame("CHAP"),
d(new ChapterFramePrivate())
{
d = new ChapterFramePrivate;
// setElementID has a workaround for a previously silly API where you had to
// specifically include the null byte.
@@ -303,9 +302,9 @@ ByteVector ChapterFrame::renderFields() const
}
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
Frame(h)
Frame(h),
d(new ChapterFramePrivate())
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -48,15 +48,17 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM")
CommentsFrame::CommentsFrame(String::Type encoding) :
Frame("COMM"),
d(new CommentsFramePrivate())
{
d = new CommentsFramePrivate;
d->textEncoding = encoding;
}
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data)
CommentsFrame::CommentsFrame(const ByteVector &data) :
Frame(data),
d(new CommentsFramePrivate())
{
d = new CommentsFramePrivate;
setData(data);
}
@@ -188,8 +190,9 @@ ByteVector CommentsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h)
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new CommentsFramePrivate())
{
d = new CommentsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -46,15 +46,15 @@ public:
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame() :
Frame("ETCO")
Frame("ETCO"),
d(new EventTimingCodesFramePrivate())
{
d = new EventTimingCodesFramePrivate;
}
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new EventTimingCodesFramePrivate())
{
d = new EventTimingCodesFramePrivate;
setData(data);
}
@@ -136,9 +136,9 @@ ByteVector EventTimingCodesFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h)
: Frame(h)
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new EventTimingCodesFramePrivate())
{
d = new EventTimingCodesFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -50,14 +50,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB")
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() :
Frame("GEOB"),
d(new GeneralEncapsulatedObjectFramePrivate())
{
d = new GeneralEncapsulatedObjectFramePrivate;
}
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data)
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) :
Frame(data),
d(new GeneralEncapsulatedObjectFramePrivate())
{
d = new GeneralEncapsulatedObjectFramePrivate;
setData(data);
}
@@ -177,8 +179,9 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h)
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new GeneralEncapsulatedObjectFramePrivate())
{
d = new GeneralEncapsulatedObjectFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -45,15 +45,17 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE")
OwnershipFrame::OwnershipFrame(String::Type encoding) :
Frame("OWNE"),
d(new OwnershipFramePrivate())
{
d = new OwnershipFramePrivate;
d->textEncoding = encoding;
}
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data)
OwnershipFrame::OwnershipFrame(const ByteVector &data) :
Frame(data),
d(new OwnershipFramePrivate())
{
d = new OwnershipFramePrivate;
setData(data);
}
@@ -161,8 +163,9 @@ ByteVector OwnershipFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h)
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new OwnershipFramePrivate())
{
d = new OwnershipFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -38,9 +38,10 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame() : Frame("PCST")
PodcastFrame::PodcastFrame() :
Frame("PCST"),
d(new PodcastFramePrivate())
{
d = new PodcastFramePrivate;
d->fieldData = ByteVector(4, '\0');
}
@@ -72,8 +73,9 @@ ByteVector PodcastFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h)
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PodcastFramePrivate())
{
d = new PodcastFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -43,14 +43,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame() : Frame("POPM")
PopularimeterFrame::PopularimeterFrame() :
Frame("POPM"),
d(new PopularimeterFramePrivate())
{
d = new PopularimeterFramePrivate;
}
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data)
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) :
Frame(data),
d(new PopularimeterFramePrivate())
{
d = new PopularimeterFramePrivate;
setData(data);
}
@@ -131,8 +133,9 @@ ByteVector PopularimeterFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h)
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PopularimeterFramePrivate())
{
d = new PopularimeterFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -45,14 +45,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame() : Frame("PRIV")
PrivateFrame::PrivateFrame() :
Frame("PRIV"),
d(new PrivateFramePrivate())
{
d = new PrivateFramePrivate;
}
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data)
PrivateFrame::PrivateFrame(const ByteVector &data) :
Frame(data),
d(new PrivateFramePrivate())
{
d = new PrivateFramePrivate;
setData(data);
}
@@ -120,8 +122,9 @@ ByteVector PrivateFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h)
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PrivateFramePrivate())
{
d = new PrivateFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -54,14 +54,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2")
RelativeVolumeFrame::RelativeVolumeFrame() :
Frame("RVA2"),
d(new RelativeVolumeFramePrivate())
{
d = new RelativeVolumeFramePrivate;
}
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data)
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) :
Frame(data),
d(new RelativeVolumeFramePrivate())
{
d = new RelativeVolumeFramePrivate;
setData(data);
}
@@ -196,8 +198,9 @@ ByteVector RelativeVolumeFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h)
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new RelativeVolumeFramePrivate())
{
d = new RelativeVolumeFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -52,16 +52,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) :
Frame("SYLT")
Frame("SYLT"),
d(new SynchronizedLyricsFramePrivate())
{
d = new SynchronizedLyricsFramePrivate;
d->textEncoding = encoding;
}
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new SynchronizedLyricsFramePrivate())
{
d = new SynchronizedLyricsFramePrivate;
setData(data);
}
@@ -234,9 +234,9 @@ ByteVector SynchronizedLyricsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h)
: Frame(h)
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new SynchronizedLyricsFramePrivate())
{
d = new SynchronizedLyricsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -82,9 +82,9 @@ namespace {
////////////////////////////////////////////////////////////////////////////////
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
ID3v2::Frame(data),
d(new TableOfContentsFramePrivate())
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
@@ -92,9 +92,9 @@ TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children,
const FrameList &embeddedFrames) :
ID3v2::Frame("CTOC")
ID3v2::Frame("CTOC"),
d(new TableOfContentsFramePrivate())
{
d = new TableOfContentsFramePrivate;
d->elementID = elementID;
strip(d->elementID);
d->childElements = children;
@@ -332,9 +332,9 @@ ByteVector TableOfContentsFrame::renderFields() const
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
const ByteVector &data, Header *h) :
Frame(h)
Frame(h),
d(new TableOfContentsFramePrivate())
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -45,16 +45,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
Frame(type)
Frame(type),
d(new TextIdentificationFramePrivate())
{
d = new TextIdentificationFramePrivate;
d->textEncoding = encoding;
}
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new TextIdentificationFramePrivate())
{
d = new TextIdentificationFramePrivate;
setData(data);
}
@@ -252,9 +252,10 @@ ByteVector TextIdentificationFrame::renderFields() const
// TextIdentificationFrame private members
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h)
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new TextIdentificationFramePrivate())
{
d = new TextIdentificationFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -45,16 +45,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) :
ID3v2::Frame(data)
ID3v2::Frame(data),
d(new UniqueFileIdentifierFramePrivate())
{
d = new UniqueFileIdentifierFramePrivate;
setData(data);
}
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) :
ID3v2::Frame("UFID")
ID3v2::Frame("UFID"),
d(new UniqueFileIdentifierFramePrivate())
{
d = new UniqueFileIdentifierFramePrivate;
d->owner = owner;
d->identifier = id;
}
@@ -141,8 +141,8 @@ ByteVector UniqueFileIdentifierFrame::renderFields() const
}
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) :
Frame(h)
Frame(h),
d(new UniqueFileIdentifierFramePrivate())
{
d = new UniqueFileIdentifierFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -38,9 +38,10 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data)
UnknownFrame::UnknownFrame(const ByteVector &data) :
Frame(data),
d(new UnknownFramePrivate())
{
d = new UnknownFramePrivate;
setData(data);
}
@@ -77,8 +78,9 @@ ByteVector UnknownFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h)
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UnknownFramePrivate())
{
d = new UnknownFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -50,16 +50,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
Frame("USLT")
Frame("USLT"),
d(new UnsynchronizedLyricsFramePrivate())
{
d = new UnsynchronizedLyricsFramePrivate;
d->textEncoding = encoding;
}
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new UnsynchronizedLyricsFramePrivate())
{
d = new UnsynchronizedLyricsFramePrivate;
setData(data);
}
@@ -118,7 +118,7 @@ PropertyMap UnsynchronizedLyricsFrame::asProperties() const
{
PropertyMap map;
String key = description().upper();
if(key.isEmpty() || key.upper() == "LYRICS")
if(key.isEmpty() || key == "LYRICS")
map.insert("LYRICS", text());
else
map.insert("LYRICS:" + key, text());
@@ -190,9 +190,9 @@ ByteVector UnsynchronizedLyricsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h)
: Frame(h)
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UnsynchronizedLyricsFramePrivate())
{
d = new UnsynchronizedLyricsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -49,10 +49,14 @@ public:
String description;
};
////////////////////////////////////////////////////////////////////////////////
// UrlLinkFrame public members
////////////////////////////////////////////////////////////////////////////////
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new UrlLinkFramePrivate())
{
d = new UrlLinkFramePrivate;
setData(data);
}
@@ -93,6 +97,10 @@ PropertyMap UrlLinkFrame::asProperties() const
return map;
}
////////////////////////////////////////////////////////////////////////////////
// UrlLinkFrame protected members
////////////////////////////////////////////////////////////////////////////////
void UrlLinkFrame::parseFields(const ByteVector &data)
{
d->url = String(data);
@@ -103,24 +111,28 @@ ByteVector UrlLinkFrame::renderFields() const
return d->url.data(String::Latin1);
}
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h)
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UrlLinkFramePrivate())
{
d = new UrlLinkFramePrivate;
parseFields(fieldData(data));
}
////////////////////////////////////////////////////////////////////////////////
// UserUrlLinkFrame public members
////////////////////////////////////////////////////////////////////////////////
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
UrlLinkFrame("WXXX")
UrlLinkFrame("WXXX"),
d(new UserUrlLinkFramePrivate())
{
d = new UserUrlLinkFramePrivate;
d->textEncoding = encoding;
}
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
UrlLinkFrame(data)
UrlLinkFrame(data),
d(new UserUrlLinkFramePrivate())
{
d = new UserUrlLinkFramePrivate;
setData(data);
}
@@ -158,7 +170,7 @@ PropertyMap UserUrlLinkFrame::asProperties() const
{
PropertyMap map;
String key = description().upper();
if(key.isEmpty() || key.upper() == "URL")
if(key.isEmpty() || key == "URL")
map.insert("URL", url());
else
map.insert("URL:" + key, url());
@@ -176,6 +188,10 @@ UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &descript
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// UserUrlLinkFrame protected members
////////////////////////////////////////////////////////////////////////////////
void UserUrlLinkFrame::parseFields(const ByteVector &data)
{
if(data.size() < 2) {
@@ -222,8 +238,9 @@ ByteVector UserUrlLinkFrame::renderFields() const
return v;
}
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h)
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) :
UrlLinkFrame(data, h),
d(new UserUrlLinkFramePrivate())
{
d = new UserUrlLinkFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -41,9 +41,9 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
ExtendedHeader::ExtendedHeader()
ExtendedHeader::ExtendedHeader() :
d(new ExtendedHeaderPrivate())
{
d = new ExtendedHeaderPrivate();
}
ExtendedHeader::~ExtendedHeader()

View File

@@ -198,15 +198,15 @@ ByteVector Frame::render() const
// protected members
////////////////////////////////////////////////////////////////////////////////
Frame::Frame(const ByteVector &data)
Frame::Frame(const ByteVector &data) :
d(new FramePrivate())
{
d = new FramePrivate;
d->header = new Header(data);
}
Frame::Frame(Header *h)
Frame::Frame(Header *h) :
d(new FramePrivate())
{
d = new FramePrivate;
d->header = h;
}
@@ -567,15 +567,15 @@ unsigned int Frame::Header::size(unsigned int version)
// public members (Frame::Header)
////////////////////////////////////////////////////////////////////////////////
Frame::Header::Header(const ByteVector &data, bool synchSafeInts)
Frame::Header::Header(const ByteVector &data, bool synchSafeInts) :
d(new HeaderPrivate())
{
d = new HeaderPrivate;
setData(data, synchSafeInts);
}
Frame::Header::Header(const ByteVector &data, unsigned int version)
Frame::Header::Header(const ByteVector &data, unsigned int version) :
d(new HeaderPrivate())
{
d = new HeaderPrivate;
setData(data, version);
}

View File

@@ -903,7 +903,7 @@ void ID3v2::Tag::parse(const ByteVector &origData)
if(d->header.extendedHeader()) {
if(!d->extendedHeader)
d->extendedHeader = new ExtendedHeader;
d->extendedHeader = new ExtendedHeader();
d->extendedHeader->setData(data);
if(d->extendedHeader->size() <= data.size()) {
frameDataPosition += d->extendedHeader->size();

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
@@ -321,55 +321,50 @@ void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
long long MPEG::File::nextFrameOffset(long long position)
{
bool foundLastSyncPattern = false;
ByteVector buffer;
ByteVector frameSyncBytes(2, '\0');
while(true) {
seek(position);
buffer = readBlock(bufferSize());
if(buffer.size() <= 0)
const ByteVector buffer = readBlock(bufferSize());
if(buffer.isEmpty())
return -1;
if(foundLastSyncPattern && secondSynchByte(buffer[0]))
return position - 1;
for(unsigned int i = 0; i < buffer.size() - 1; i++) {
if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1]))
return position + i;
for(size_t i = 0; i < buffer.size(); ++i) {
frameSyncBytes[0] = frameSyncBytes[1];
frameSyncBytes[1] = buffer[i];
if(isFrameSync(frameSyncBytes)) {
const Header header(this, position + i - 1, true);
if(header.isValid())
return position + i - 1;
}
}
foundLastSyncPattern = firstSyncByte(buffer[buffer.size() - 1]);
position += buffer.size();
position += bufferSize();
}
}
long long MPEG::File::previousFrameOffset(long long position)
{
bool foundFirstSyncPattern = false;
ByteVector buffer;
ByteVector frameSyncBytes(2, '\0');
while(position > 0) {
size_t size = static_cast<size_t>(std::min<long long>(position, bufferSize()));
position -= size;
const long long bufferLength = std::min<long long>(position, bufferSize());
position -= bufferLength;
seek(position);
buffer = readBlock(size);
const ByteVector buffer = readBlock(static_cast<size_t>(bufferLength));
if(buffer.isEmpty())
break;
if(foundFirstSyncPattern && firstSyncByte(buffer[buffer.size() - 1]))
return position + buffer.size() - 1;
for(int i = static_cast<int>(buffer.size()) - 2; i >= 0; i--) {
if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1]))
return position + i;
for(int i = static_cast<int>(buffer.size()) - 1; i >= 0; --i) {
frameSyncBytes[1] = frameSyncBytes[0];
frameSyncBytes[0] = buffer[i];
if(isFrameSync(frameSyncBytes)) {
const Header header(this, position + i, true);
if(header.isValid())
return position + i + header.frameLength();
}
}
foundFirstSyncPattern = secondSynchByte(buffer[0]);
}
return -1;
}
@@ -463,28 +458,41 @@ long long MPEG::File::findID3v2()
const ByteVector headerID = ID3v2::Header::fileIdentifier();
seek(0);
const ByteVector data = readBlock(headerID.size());
if(data.size() < headerID.size())
return -1;
if(data == headerID)
if(readBlock(headerID.size()) == headerID)
return 0;
if(firstSyncByte(data[0]) && secondSynchByte(data[1]))
const Header firstHeader(this, 0, true);
if(firstHeader.isValid())
return -1;
// Look for the entire file, if neither an MEPG frame or ID3v2 tag was found
// at the beginning of the file.
// We don't care about the inefficiency of the code, since this is a seldom case.
// Look for an ID3v2 tag until reaching the first valid MPEG frame.
const long long tagOffset = find(headerID);
if(tagOffset < 0)
return -1;
ByteVector frameSyncBytes(2, '\0');
ByteVector tagHeaderBytes(3, '\0');
long long position = 0;
const long long frameOffset = firstFrameOffset();
if(frameOffset < tagOffset)
return -1;
while(true) {
seek(position);
const ByteVector buffer = readBlock(bufferSize());
if(buffer.isEmpty())
return -1;
return tagOffset;
for(size_t i = 0; i < buffer.size(); ++i) {
frameSyncBytes[0] = frameSyncBytes[1];
frameSyncBytes[1] = buffer[i];
if(isFrameSync(frameSyncBytes)) {
const Header header(this, position + i - 1, true);
if(header.isValid())
return -1;
}
tagHeaderBytes[0] = tagHeaderBytes[1];
tagHeaderBytes[1] = tagHeaderBytes[2];
tagHeaderBytes[2] = buffer[i];
if(tagHeaderBytes == headerID)
return position + i - 2;
}
position += bufferSize();
}
}

View File

@@ -182,7 +182,7 @@ void MPEG::Header::parse(File *file, long long offset, bool checkLength)
// Check for the MPEG synch bytes.
if(!firstSyncByte(data[0]) || !secondSynchByte(data[1])) {
if(!isFrameSync(data)) {
debug("MPEG::Header::parse() -- MPEG header did not match MPEG synch.");
return;
}

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
@@ -152,23 +152,13 @@ void MPEG::AudioProperties::read(File *file)
{
// Only the first valid frame is required if we have a VBR header.
long long firstFrameOffset = file->firstFrameOffset();
const long long firstFrameOffset = file->firstFrameOffset();
if(firstFrameOffset < 0) {
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
return;
}
Header firstHeader(file, firstFrameOffset);
while(!firstHeader.isValid()) {
firstFrameOffset = file->nextFrameOffset(firstFrameOffset + 1);
if(firstFrameOffset < 0) {
debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream.");
return;
}
firstHeader = Header(file, firstFrameOffset);
}
const Header firstHeader(file, firstFrameOffset, false);
// Check for a VBR header that will help us in gathering information about a
// VBR stream.
@@ -200,24 +190,13 @@ void MPEG::AudioProperties::read(File *file)
// Look for the last MPEG audio frame to calculate the stream length.
long long lastFrameOffset = file->lastFrameOffset();
const long long lastFrameOffset = file->lastFrameOffset();
if(lastFrameOffset < 0) {
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
return;
}
Header lastHeader(file, lastFrameOffset, false);
while(!lastHeader.isValid()) {
lastFrameOffset = file->previousFrameOffset(lastFrameOffset);
if(lastFrameOffset < 0) {
debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.");
return;
}
lastHeader = Header(file, lastFrameOffset, false);
}
const Header lastHeader(file, lastFrameOffset, false);
const long long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength();
if(streamLength > 0)
d->length = static_cast<int>(streamLength * 8.0 / d->bitrate + 0.5);

View File

@@ -41,17 +41,17 @@ namespace TagLib
* MPEG frames can be recognized by the bit pattern 11111111 111, so the
* first byte is easy to check for, however checking to see if the second byte
* starts with \e 111 is a bit more tricky, hence these functions.
*
* \note This does not check the length of the vector, since this is an
* internal utility function.
*/
inline bool firstSyncByte(unsigned char byte)
inline bool isFrameSync(const ByteVector &bytes)
{
return (byte == 0xFF);
}
// 0xFF in the second byte is possible in theory, but it's very unlikely.
inline bool secondSynchByte(unsigned char byte)
{
// 0xFF is possible in theory, but it's very unlikely be a header.
return (byte != 0xFF && ((byte & 0xE0) == 0xE0));
const unsigned char b1 = bytes[0];
const unsigned char b2 = bytes[1];
return (b1 == 0xFF && b2 != 0xFF && (b2 & 0xE0) == 0xE0);
}
}

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2004-2005 by Allan Sandfeld Jensen
email : kde@carewolf.org
***************************************************************************/
@@ -70,17 +70,19 @@ public:
////////////////////////////////////////////////////////////////////////////////
Ogg::FLAC::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) : Ogg::File(file)
AudioProperties::ReadStyle propertiesStyle) :
Ogg::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
if(isOpen())
read(readProperties, propertiesStyle);
}
Ogg::FLAC::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) : Ogg::File(stream)
AudioProperties::ReadStyle propertiesStyle) :
Ogg::File(stream),
d(new FilePrivate())
{
d = new FilePrivate;
if(isOpen())
read(readProperties, propertiesStyle);
}
@@ -161,7 +163,7 @@ void Ogg::FLAC::File::read(bool readProperties, AudioProperties::ReadStyle prope
if(d->hasXiphComment)
d->comment = new Ogg::XiphComment(xiphCommentData());
else
d->comment = new Ogg::XiphComment;
d->comment = new Ogg::XiphComment();
if(readProperties)

View File

@@ -113,9 +113,6 @@ namespace TagLib {
/*!
* Save the file. This will primarily save and update the XiphComment.
* Returns true if the save is successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. It leads to a segfault.
*/
virtual bool save();

View File

@@ -91,7 +91,7 @@ Opus::AudioProperties *Opus::File::audioProperties() const
bool Opus::File::save()
{
if(!d->comment)
d->comment = new Ogg::XiphComment;
d->comment = new Ogg::XiphComment();
setPacket(1, ByteVector("OpusTags", 8) + d->comment->render(false));

View File

@@ -98,9 +98,6 @@ namespace TagLib {
* Save the file.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. It leads to a segfault.
*/
virtual bool save();

View File

@@ -91,7 +91,7 @@ Speex::AudioProperties *Speex::File::audioProperties() const
bool Speex::File::save()
{
if(!d->comment)
d->comment = new Ogg::XiphComment;
d->comment = new Ogg::XiphComment();
setPacket(1, d->comment->render());

View File

@@ -98,9 +98,6 @@ namespace TagLib {
* Save the file.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. It leads to a segfault.
*/
virtual bool save();

View File

@@ -99,7 +99,7 @@ bool Ogg::Vorbis::File::save()
ByteVector v(vorbisCommentHeaderID);
if(!d->comment)
d->comment = new Ogg::XiphComment;
d->comment = new Ogg::XiphComment();
v.append(d->comment->render());
setPacket(1, v);

View File

@@ -96,9 +96,6 @@ namespace TagLib {
* Save the file.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. It leads to a segfault.
*/
virtual bool save();

View File

@@ -206,7 +206,7 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate)
{
if(d->chunks.size() == 0) {
if(d->chunks.empty()) {
debug("RIFF::File::setChunkData - No valid chunks found.");
return;
}

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
@@ -60,10 +60,6 @@ public:
unsigned char bpmSpeed;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
S3M::AudioProperties::AudioProperties(AudioProperties::ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/

View File

@@ -53,9 +53,9 @@ ByteVectorStream::ByteVectorStreamPrivate::ByteVectorStreamPrivate(const ByteVec
// public members
////////////////////////////////////////////////////////////////////////////////
ByteVectorStream::ByteVectorStream(const ByteVector &data)
ByteVectorStream::ByteVectorStream(const ByteVector &data) :
d(new ByteVectorStreamPrivate(data))
{
d = new ByteVectorStreamPrivate(data);
}
ByteVectorStream::~ByteVectorStream()

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
@@ -33,53 +33,25 @@
using namespace TagLib;
class File::FilePrivateBase
class File::FilePrivate
{
public:
FilePrivateBase() :
FilePrivate(IOStream *stream, bool owner) :
stream(stream),
streamOwner(owner),
valid(true) {}
virtual ~FilePrivateBase() {}
virtual IOStream *stream() const = 0;
~FilePrivate()
{
if(streamOwner)
delete stream;
}
IOStream *stream;
bool streamOwner;
bool valid;
};
// FilePrivate implementation which takes ownership of the stream.
class File::ManagedFilePrivate : public File::FilePrivateBase
{
public:
ManagedFilePrivate(IOStream *stream) :
p(stream) {}
virtual IOStream *stream() const
{
return p.get();
}
private:
SCOPED_PTR<IOStream> p;
};
// FilePrivate implementation which doesn't take ownership of the stream.
class File::UnmanagedFilePrivate : public File::FilePrivateBase
{
public:
UnmanagedFilePrivate(IOStream *stream) :
p(stream) {}
virtual IOStream *stream() const
{
return p;
}
private:
IOStream *p;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
@@ -91,7 +63,7 @@ File::~File()
FileName File::name() const
{
return d->stream()->name();
return d->stream->name();
}
PropertyMap File::properties() const
@@ -111,17 +83,17 @@ PropertyMap File::setProperties(const PropertyMap &properties)
ByteVector File::readBlock(size_t length)
{
return d->stream()->readBlock(length);
return d->stream->readBlock(length);
}
void File::writeBlock(const ByteVector &data)
{
d->stream()->writeBlock(data);
d->stream->writeBlock(data);
}
long long File::find(const ByteVector &pattern, long long fromOffset, const ByteVector &before)
{
if(!d->stream() || pattern.size() > bufferSize())
if(!d->stream || pattern.size() > bufferSize())
return -1;
// The position in the file that the current buffer starts at.
@@ -225,7 +197,7 @@ long long File::find(const ByteVector &pattern, long long fromOffset, const Byte
long long File::rfind(const ByteVector &pattern, long long fromOffset, const ByteVector &before)
{
if(!d->stream() || pattern.size() > bufferSize())
if(!d->stream || pattern.size() > bufferSize())
return -1;
// Save the location of the current read pointer. We will restore the
@@ -287,22 +259,22 @@ long long File::rfind(const ByteVector &pattern, long long fromOffset, const Byt
void File::insert(const ByteVector &data, long long start, size_t replace)
{
d->stream()->insert(data, start, replace);
d->stream->insert(data, start, replace);
}
void File::removeBlock(long long start, size_t length)
{
d->stream()->removeBlock(start, length);
d->stream->removeBlock(start, length);
}
bool File::readOnly() const
{
return d->stream()->readOnly();
return d->stream->readOnly();
}
bool File::isOpen() const
{
return d->stream()->isOpen();
return d->stream->isOpen();
}
bool File::isValid() const
@@ -312,27 +284,27 @@ bool File::isValid() const
void File::seek(long long offset, Position p)
{
d->stream()->seek(offset, IOStream::Position(p));
d->stream->seek(offset, IOStream::Position(p));
}
void File::truncate(long long length)
{
d->stream()->truncate(length);
d->stream->truncate(length);
}
void File::clear()
{
d->stream()->clear();
d->stream->clear();
}
long long File::tell() const
{
return d->stream()->tell();
return d->stream->tell();
}
long long File::length()
{
return d->stream()->length();
return d->stream->length();
}
String File::toString() const
@@ -353,13 +325,13 @@ String File::toString() const
// protected members
////////////////////////////////////////////////////////////////////////////////
File::File(const FileName &fileName)
: d(new ManagedFilePrivate(new FileStream(fileName)))
File::File(const FileName &fileName) :
d(new FilePrivate(new FileStream(fileName), true))
{
}
File::File(IOStream *stream)
: d(new UnmanagedFilePrivate(stream))
File::File(IOStream *stream) :
d(new FilePrivate(stream, false))
{
}

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
@@ -282,10 +282,8 @@ namespace TagLib {
File(const File &);
File &operator=(const File &);
class FilePrivateBase;
class ManagedFilePrivate;
class UnmanagedFilePrivate;
FilePrivateBase *d;
class FilePrivate;
FilePrivate *d;
};
}

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2013 by Tsuda Kageyu
email : tsuda.kageyu@gmail.com
***************************************************************************/

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2013 by Tsuda Kageyu
email : tsuda.kageyu@gmail.com
***************************************************************************/

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
@@ -23,24 +23,14 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
// This class assumes that std::basic_string<T> has a contiguous and null-terminated buffer.
#include <iostream>
#include <cstring>
#include <cwchar>
#include <cerrno>
#include <climits>
#ifdef _WIN32
# include <windows.h>
#else
# include "unicode.h"
#endif
#include <tdebug.h>
#include <tstringlist.h>
#include <tsmartptr.h>
#include <tutils.h>
#include <utf8/checked.h>
#include "tstring.h"
@@ -48,72 +38,6 @@ namespace
{
using namespace TagLib;
size_t UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength)
{
size_t len = 0;
#ifdef _WIN32
len = ::WideCharToMultiByte(
CP_UTF8, 0, src, static_cast<int>(srcLength), dst, static_cast<int>(dstLength), NULL, NULL);
#else
using namespace Unicode;
const UTF16 *srcBegin = src;
const UTF16 *srcEnd = srcBegin + srcLength;
UTF8 *dstBegin = reinterpret_cast<UTF8*>(dst);
UTF8 *dstEnd = dstBegin + dstLength;
ConversionResult result = ConvertUTF16toUTF8(
&srcBegin, srcEnd, &dstBegin, dstEnd, lenientConversion);
if(result == conversionOK)
len = dstBegin - reinterpret_cast<UTF8*>(dst);
#endif
if(len == 0)
debug("String::UTF16toUTF8() - Unicode conversion error.");
return len;
}
size_t UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength)
{
size_t len = 0;
#ifdef _WIN32
len = ::MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, src, static_cast<int>(srcLength), dst, static_cast<int>(dstLength));
#else
using namespace Unicode;
const UTF8 *srcBegin = reinterpret_cast<const UTF8*>(src);
const UTF8 *srcEnd = srcBegin + srcLength;
UTF16 *dstBegin = dst;
UTF16 *dstEnd = dstBegin + dstLength;
ConversionResult result = ConvertUTF8toUTF16(
&srcBegin, srcEnd, &dstBegin, dstEnd, lenientConversion);
if(result == conversionOK)
len = dstBegin - dst;
#endif
if(len == 0)
debug("String::UTF8toUTF16() - Unicode conversion error.");
return len;
}
// Returns the native format of std::wstring.
String::Type wcharByteOrder()
{
@@ -139,28 +63,60 @@ namespace
{
data.resize(length);
if(length > 0) {
const size_t len = UTF8toUTF16(s, length, &data[0], data.size());
data.resize(len);
try {
const std::wstring::iterator dstEnd = utf8::utf8to16(s, s + length, data.begin());
data.resize(dstEnd - data.begin());
}
catch(const utf8::exception &e) {
debug(String("String::copyFromUTF8() - UTF8-CPP error: ") + e.what());
data.clear();
}
}
// Helper functions to read a UTF-16 character from an array.
template <typename T>
unsigned short nextUTF16(const T **p);
template <>
unsigned short nextUTF16<wchar_t>(const wchar_t **p)
{
return static_cast<unsigned short>(*(*p)++);
}
template <>
unsigned short nextUTF16<char>(const char **p)
{
union {
unsigned short w;
char c[2];
} u;
u.c[0] = *(*p)++;
u.c[1] = *(*p)++;
return u.w;
}
// Converts a UTF-16 (with BOM), UTF-16LE or UTF16-BE string into
// UTF-16(without BOM/CPU byte order) and copies it to the internal buffer.
void copyFromUTF16(std::wstring &data, const wchar_t *s, size_t length, String::Type t)
template <typename T>
void copyFromUTF16(std::wstring &data, const T *s, size_t length, String::Type t)
{
bool swap;
if(t == String::UTF16) {
if(length >= 1 && s[0] == 0xfeff)
swap = false; // Same as CPU endian. No need to swap bytes.
else if(length >= 1 && s[0] == 0xfffe)
swap = true; // Not same as CPU endian. Need to swap bytes.
else {
debug("String::copyFromUTF16() - Invalid UTF16 string.");
if(length < 1) {
debug("String::copyFromUTF16() - Invalid UTF16 string. Too short to have a BOM.");
return;
}
const unsigned short bom = nextUTF16(&s);
if(bom == 0xfeff)
swap = false; // Same as CPU endian. No need to swap bytes.
else if(bom == 0xfffe)
swap = true; // Not same as CPU endian. Need to swap bytes.
else {
debug("String::copyFromUTF16() - Invalid UTF16 string. BOM is broken.");
return;
}
s++;
length--;
}
else {
@@ -168,57 +124,12 @@ namespace
}
data.resize(length);
if(length > 0) {
if(swap) {
for(size_t i = 0; i < length; ++i)
data[i] = Utils::byteSwap(static_cast<unsigned short>(s[i]));
}
else {
::wmemcpy(&data[0], s, length);
}
}
}
// Converts a UTF-16 (with BOM), UTF-16LE or UTF16-BE string into
// UTF-16(without BOM/CPU byte order) and copies it to the internal buffer.
void copyFromUTF16(std::wstring &data, const char *s, size_t length, String::Type t)
{
bool swap;
if(t == String::UTF16) {
if(length < 2) {
debug("String::copyFromUTF16() - Invalid UTF16 string.");
return;
}
// Uses memcpy instead of reinterpret_cast to avoid an alignment exception.
unsigned short bom;
::memcpy(&bom, s, 2);
if(bom == 0xfeff)
swap = false; // Same as CPU endian. No need to swap bytes.
else if(bom == 0xfffe)
swap = true; // Not same as CPU endian. Need to swap bytes.
else {
debug("String::copyFromUTF16() - Invalid UTF16 string.");
return;
}
s += 2;
length -= 2;
}
else {
swap = (t != wcharByteOrder());
}
data.resize(length / 2);
for(size_t i = 0; i < length / 2; ++i) {
unsigned short c;
::memcpy(&c, s, 2);
for(size_t i = 0; i < length; ++i) {
const unsigned short c = nextUTF16(&s);
if(swap)
c = Utils::byteSwap(c);
data[i] = static_cast<wchar_t>(c);
s += 2;
data[i] = Utils::byteSwap(c);
else
data[i] = c;
}
}
}
@@ -354,7 +265,7 @@ String::String(const ByteVector &v, Type t) :
else if(t == UTF8)
copyFromUTF8(*d->data, v.data(), v.size());
else
copyFromUTF16(*d->data, v.data(), v.size(), t);
copyFromUTF16(*d->data, v.data(), v.size() / 2, t);
// If we hit a null in the ByteVector, shrink the string again.
d->data->resize(::wcslen(d->data->c_str()));
@@ -469,12 +380,14 @@ String & String::clear()
String String::upper() const
{
static const int shift = 'A' - 'a';
String s;
s.d->data->reserve(size());
String s(*d->data);
for(Iterator it = s.begin(); it != s.end(); ++it) {
for(ConstIterator it = begin(); it != end(); ++it) {
if(*it >= 'a' && *it <= 'z')
*it = *it + shift;
s.d->data->push_back(*it + 'A' - 'a');
else
s.d->data->push_back(*it);
}
return s;
@@ -504,24 +417,26 @@ ByteVector String::data(Type t) const
ByteVector v(size(), 0);
char *p = v.data();
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it)
for(ConstIterator it = begin(); it != end(); ++it)
*p++ = static_cast<char>(*it);
return v;
}
case UTF8:
if(!d->data->empty())
{
ByteVector v(size() * 4 + 1, 0);
ByteVector v(size() * 4, 0);
const size_t len = UTF16toUTF8(d->data->c_str(), d->data->size(), v.data(), v.size());
v.resize(len);
try {
const ByteVector::Iterator dstEnd = utf8::utf16to8(begin(), end(), v.begin());
v.resize(static_cast<unsigned int>(dstEnd - v.begin()));
}
catch(const utf8::exception &e) {
debug(String("String::data() - UTF8-CPP error: ") + e.what());
v.clear();
}
return v;
}
else {
return ByteVector();
}
case UTF16:
{
ByteVector v(2 + size() * 2, 0);
@@ -532,7 +447,7 @@ ByteVector String::data(Type t) const
*p++ = '\xff';
*p++ = '\xfe';
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
for(ConstIterator it = begin(); it != end(); ++it) {
*p++ = static_cast<char>(*it & 0xff);
*p++ = static_cast<char>(*it >> 8);
}
@@ -544,7 +459,7 @@ ByteVector String::data(Type t) const
ByteVector v(size() * 2, 0);
char *p = v.data();
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
for(ConstIterator it = begin(); it != end(); ++it) {
*p++ = static_cast<char>(*it >> 8);
*p++ = static_cast<char>(*it & 0xff);
}
@@ -556,7 +471,7 @@ ByteVector String::data(Type t) const
ByteVector v(size() * 2, 0);
char *p = v.data();
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
for(ConstIterator it = begin(); it != end(); ++it) {
*p++ = static_cast<char>(*it & 0xff);
*p++ = static_cast<char>(*it >> 8);
}
@@ -601,7 +516,7 @@ String String::stripWhiteSpace() const
bool String::isLatin1() const
{
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
for(ConstIterator it = begin(); it != end(); ++it) {
if(*it >= 256)
return false;
}
@@ -610,7 +525,7 @@ bool String::isLatin1() const
bool String::isAscii() const
{
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
for(ConstIterator it = begin(); it != end(); ++it) {
if(*it >= 128)
return false;
}

View File

@@ -34,9 +34,7 @@
# include <config.h>
#endif
#if defined(HAVE_BOOST_BYTESWAP)
# include <boost/endian/conversion.hpp>
#elif defined(HAVE_MSC_BYTESWAP)
#if defined(HAVE_MSC_BYTESWAP)
# include <stdlib.h>
#elif defined(HAVE_GLIBC_BYTESWAP)
# include <byteswap.h>
@@ -63,11 +61,7 @@ namespace TagLib
*/
inline unsigned short byteSwap(unsigned short x)
{
#if defined(HAVE_BOOST_BYTESWAP)
return boost::endian::endian_reverse(static_cast<uint16_t>(x));
#elif defined(HAVE_GCC_BYTESWAP)
#if defined(HAVE_GCC_BYTESWAP)
return __builtin_bswap16(x);
@@ -99,11 +93,7 @@ namespace TagLib
*/
inline unsigned int byteSwap(unsigned int x)
{
#if defined(HAVE_BOOST_BYTESWAP)
return boost::endian::endian_reverse(static_cast<uint32_t>(x));
#elif defined(HAVE_GCC_BYTESWAP)
#if defined(HAVE_GCC_BYTESWAP)
return __builtin_bswap32(x);
@@ -138,11 +128,7 @@ namespace TagLib
*/
inline unsigned long long byteSwap(unsigned long long x)
{
#if defined(HAVE_BOOST_BYTESWAP)
return boost::endian::endian_reverse(static_cast<uint64_t>(x));
#elif defined(HAVE_GCC_BYTESWAP)
#if defined(HAVE_GCC_BYTESWAP)
return __builtin_bswap64(x);

View File

@@ -1,303 +0,0 @@
/*******************************************************************************
* *
* THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB *
* AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. *
* AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. *
* *
*******************************************************************************/
/*
* Copyright 2001 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/*
* This file has been modified by Scott Wheeler <wheeler@kde.org> to remove
* the UTF32 conversion functions and to place the appropriate functions
* in their own C++ namespace.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "unicode.h"
#include <stdio.h>
#define UNI_SUR_HIGH_START (UTF32)0xD800
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
#define false 0
#define true 1
namespace Unicode {
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
*/
static const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... six byte sequence.)
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END && source < sourceEnd) {
UTF32 ch2 = *source;
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else if ((flags == strictConversion) && (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
/* Figure out how many bytes the result will require */
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch < (UTF32)0x200000) { bytesToWrite = 4;
} else { bytesToWrite = 2;
ch = UNI_REPLACEMENT_CHAR;
}
// printf("bytes to write = %i\n", bytesToWrite);
target += bytesToWrite;
if (target > targetEnd) {
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (ch | byteMark) & byteMask; ch >>= 6;
case 3: *--target = (ch | byteMark) & byteMask; ch >>= 6;
case 2: *--target = (ch | byteMark) & byteMask; ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static Boolean isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
if (*source > 0xF4) return false;
}
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
return false;
}
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
if ((flags == strictConversion) && (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_UTF16) {
if (flags == strictConversion) {
result = sourceIllegal;
source -= (extraBytesToRead+1); /* return to the start */
break; /* Bail out; shouldn't continue */
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (ch & halfMask) + UNI_SUR_LOW_START;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */

View File

@@ -1,149 +0,0 @@
#ifndef TAGLIB_UNICODE_H
#define TAGLIB_UNICODE_H
/*******************************************************************************
* *
* THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB *
* AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. *
* AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. *
* *
*******************************************************************************/
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
/*
* Copyright 2001 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/*
* This file has been modified by Scott Wheeler <wheeler@kde.org> to remove
* the UTF32 conversion functions and to place the appropriate functions
* in their own C++ namespace.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several functions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
namespace Unicode {
typedef unsigned long UTF32; /* at least 32 bits */
typedef wchar_t UTF16; /* TagLib assumes that wchar_t is sufficient for UTF-16. */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
typedef enum {
conversionOK = 0, /* conversion successful */
sourceExhausted = 1, /* partial character in source, but hit end */
targetExhausted = 2, /* insuff. room in target for conversion */
sourceIllegal = 3 /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
} // namespace Unicode
/* --------------------------------------------------------------------- */
#endif
#endif

View File

@@ -0,0 +1,327 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t cp) : cp(cp) {}
virtual const char* what() const throw() { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const throw() { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const throw() { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const throw() { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
throw not_enough_room();
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
/// Deprecated in versions that include "prior"
template <typename octet_iterator>
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
{
octet_iterator end = it;
while (utf8::internal::is_trail(*(--it)))
if (it == pass_start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
octet_iterator temp = it;
return utf8::next(temp, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
for (distance_type i = 0; i < n; ++i)
utf8::next(it, end);
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start != end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start != end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& range_start,
const octet_iterator& range_end) :
it(octet_it), range_start(range_start), range_end(range_end)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#endif //header guard

329
taglib/toolkit/utf8/core.h Normal file
View File

@@ -0,0 +1,329 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
//Deprecated in release 2.3
template <typename octet_iterator>
inline bool is_bom (octet_iterator it)
{
return (
(utf8::internal::mask8(*it++)) == bom[0] &&
(utf8::internal::mask8(*it++)) == bom[1] &&
(utf8::internal::mask8(*it)) == bom[2]
);
}
} // namespace utf8
#endif // header guard

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
@@ -56,10 +56,6 @@ public:
unsigned short bpmSpeed;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
XM::AudioProperties::AudioProperties(AudioProperties::ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())

Binary file not shown.

BIN
tests/data/garbage.mp3 Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -233,7 +233,7 @@ public:
FileRef f1(TEST_FILE_PATH_C("no-extension"));
CPPUNIT_ASSERT(f1.isNull());
FileRef f2(TEST_FILE_PATH_C("unsupported-extension.xxx"));
FileRef f2(TEST_FILE_PATH_C("unsupported-extension.xx"));
CPPUNIT_ASSERT(f2.isNull());
}

View File

@@ -63,6 +63,7 @@ class TestFLAC : public CppUnit::TestFixture
CPPUNIT_TEST(testEmptyID3v2);
CPPUNIT_TEST(testStripTags);
CPPUNIT_TEST(testRemoveXiphField);
CPPUNIT_TEST(testEmptySeekTable);
CPPUNIT_TEST_SUITE_END();
public:
@@ -516,6 +517,24 @@ public:
}
}
void testEmptySeekTable()
{
ScopedFileCopy copy("empty-seektable", ".flac");
{
FLAC::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.isValid());
f.xiphComment(true)->setTitle("XiphComment Title");
f.save();
}
{
FLAC::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.isValid());
f.seek(42);
const ByteVector data = f.readBlock(4);
CPPUNIT_ASSERT_EQUAL(ByteVector("\x03\x00\x00\x00", 4), data);
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC);

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2007 by Lukas Lalinsky
email : lukas@oxygene.sk
***************************************************************************/
@@ -64,6 +64,7 @@ class TestMPEG : public CppUnit::TestFixture
CPPUNIT_TEST(testEmptyID3v2);
CPPUNIT_TEST(testEmptyID3v1);
CPPUNIT_TEST(testEmptyAPE);
CPPUNIT_TEST(testIgnoreGarbage);
CPPUNIT_TEST_SUITE_END();
public:
@@ -96,7 +97,7 @@ public:
void testAudioPropertiesVBRIHeader()
{
MPEG::File f(TEST_FILE_PATH_C("vbri.mp3"));
MPEG::File f(TEST_FILE_PATH_C("rare_frames.mp3"));
CPPUNIT_ASSERT(f.audioProperties());
CPPUNIT_ASSERT_EQUAL(222, f.audioProperties()->length());
CPPUNIT_ASSERT_EQUAL(222, f.audioProperties()->lengthInSeconds());
@@ -119,13 +120,8 @@ public:
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
CPPUNIT_ASSERT(!f.audioProperties()->xingHeader());
long long last = f.lastFrameOffset();
MPEG::Header lastHeader(&f, last, false);
while(!lastHeader.isValid()) {
last = f.previousFrameOffset(last);
lastHeader = MPEG::Header(&f, last, false);
}
const long long last = f.lastFrameOffset();
const MPEG::Header lastHeader(&f, last, false);
CPPUNIT_ASSERT_EQUAL(28213LL, last);
CPPUNIT_ASSERT_EQUAL(209, lastHeader.frameLength());
@@ -163,7 +159,7 @@ public:
CPPUNIT_ASSERT(f.audioProperties());
CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length());
CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds());
CPPUNIT_ASSERT_EQUAL(176, f.audioProperties()->lengthInMilliseconds());
CPPUNIT_ASSERT_EQUAL(183, f.audioProperties()->lengthInMilliseconds());
CPPUNIT_ASSERT_EQUAL(320, f.audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
@@ -421,6 +417,27 @@ public:
}
}
void testIgnoreGarbage()
{
const ScopedFileCopy copy("garbage", ".mp3");
{
MPEG::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.isValid());
CPPUNIT_ASSERT(f.hasID3v2Tag());
CPPUNIT_ASSERT_EQUAL(2255LL, f.firstFrameOffset());
CPPUNIT_ASSERT_EQUAL(6015LL, f.lastFrameOffset());
CPPUNIT_ASSERT_EQUAL(String("Title A"), f.ID3v2Tag()->title());
f.ID3v2Tag()->setTitle("Title B");
f.save();
}
{
MPEG::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.isValid());
CPPUNIT_ASSERT(f.hasID3v2Tag());
CPPUNIT_ASSERT_EQUAL(String("Title B"), f.ID3v2Tag()->title());
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG);

View File

@@ -49,8 +49,9 @@ class TestString : public CppUnit::TestFixture
CPPUNIT_TEST(testUpper);
CPPUNIT_TEST(testEncodeNonLatin1);
CPPUNIT_TEST(testEncodeEmpty);
CPPUNIT_TEST(testEncodeNonBMP);
CPPUNIT_TEST(testIterator);
CPPUNIT_TEST(testRedundantUTF8);
CPPUNIT_TEST(testInvalidUTF8);
CPPUNIT_TEST_SUITE_END();
public:
@@ -174,6 +175,15 @@ public:
const String s2(v2, String::UTF8);
CPPUNIT_ASSERT_EQUAL(s2.data(String::UTF16), v1);
const ByteVector v3("\xfe\xff\xd8\x01\x30\x42");
CPPUNIT_ASSERT(String(v3, String::UTF16).data(String::UTF8).isEmpty());
const ByteVector v4("\xfe\xff\x30\x42\xdc\x01");
CPPUNIT_ASSERT(String(v4, String::UTF16).data(String::UTF8).isEmpty());
const ByteVector v5("\xfe\xff\xdc\x01\xd8\x01");
CPPUNIT_ASSERT(String(v5, String::UTF16).data(String::UTF8).isEmpty());
}
void testAppendStringDetach()
@@ -321,6 +331,13 @@ public:
CPPUNIT_ASSERT(empty.to8Bit(true).empty());
}
void testEncodeNonBMP()
{
const ByteVector a("\xFF\xFE\x3C\xD8\x50\xDD\x40\xD8\xF5\xDC\x3C\xD8\x00\xDE", 14);
const ByteVector b("\xF0\x9F\x85\x90\xF0\xA0\x83\xB5\xF0\x9F\x88\x80");
CPPUNIT_ASSERT_EQUAL(b, String(a, String::UTF16).data(String::UTF8));
}
void testIterator()
{
String s1 = "taglib string";
@@ -339,12 +356,26 @@ public:
CPPUNIT_ASSERT_EQUAL(L'I', *it2);
}
void testRedundantUTF8()
void testInvalidUTF8()
{
CPPUNIT_ASSERT_EQUAL(String("/"), String(ByteVector("\x2F"), String::UTF8));
CPPUNIT_ASSERT(String(ByteVector("\xC0\xAF"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xE0\x80\xAF"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xF0\x80\x80\xAF"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xF8\x80\x80\x80\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xFC\x80\x80\x80\x80\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xC2"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xE0\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xF0\x80\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xF8\x80\x80\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xFC\x80\x80\x80\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String('\x80', String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xED\xA0\x80\xED\xB0\x80"), String::UTF8).isEmpty());
CPPUNIT_ASSERT(String(ByteVector("\xED\xB0\x80\xED\xA0\x80"), String::UTF8).isEmpty());
}
};