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

# Conflicts:
#	config.h.cmake
#	taglib/ogg/xiphcomment.cpp
#	taglib/taglib_config.h.cmake
#	taglib/toolkit/tbytevector.cpp
#	taglib/toolkit/trefcounter.cpp
#	taglib/toolkit/tstring.cpp
#	taglib/toolkit/tutils.h
#	taglib/toolkit/tzlib.cpp
#	taglib/xm/xmfile.cpp
#	tests/test_string.cpp
#	tests/test_xiphcomment.cpp
This commit is contained in:
Tsuda Kageyu 2016-12-13 13:52:35 +09:00
commit d8114059ee
29 changed files with 397 additions and 286 deletions

View File

@ -13,6 +13,14 @@ if(DEFINED ENABLE_STATIC)
endif()
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
if(APPLE)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
if(BUILD_FRAMEWORK)
set(BUILD_SHARED_LIBS ON)
#set(CMAKE_MACOSX_RPATH 1)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
endif()
if(NOT BUILD_SHARED_LIBS)
add_definitions(-DTAGLIB_STATIC)
endif()
@ -48,11 +56,6 @@ set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The subdirectory to
set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})")
set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix")
if(APPLE)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")

View File

@ -57,64 +57,55 @@ endif()
check_cxx_source_compiles("
#include <atomic>
int main() {
std::atomic<unsigned int> x;
x.fetch_add(1);
x.fetch_sub(1);
std::atomic_int x;
++x;
--x;
return 0;
}
" HAVE_STD_ATOMIC)
if(NOT HAVE_STD_ATOMIC)
find_package(Boost COMPONENTS atomic)
if(Boost_ATOMIC_FOUND)
set(HAVE_BOOST_ATOMIC 1)
else()
set(HAVE_BOOST_ATOMIC 0)
endif()
check_cxx_source_compiles("
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_GCC_ATOMIC)
if(NOT HAVE_BOOST_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
return 0;
}
" HAVE_GCC_ATOMIC)
" HAVE_MAC_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
#include <windows.h>
int main() {
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
return 0;
}
" HAVE_MAC_ATOMIC)
" HAVE_WIN_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <windows.h>
#include <ia64intrin.h>
int main() {
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_WIN_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <ia64intrin.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_IA64_ATOMIC)
endif()
" HAVE_IA64_ATOMIC)
endif()
endif()
endif()
@ -259,15 +250,6 @@ if(NOT ZLIB_SOURCE)
else()
set(HAVE_ZLIB 0)
endif()
if(NOT HAVE_ZLIB)
find_package(Boost COMPONENTS iostreams zlib)
if(Boost_IOSTREAMS_FOUND AND Boost_ZLIB_FOUND)
set(HAVE_BOOST_ZLIB 1)
else()
set(HAVE_BOOST_ZLIB 0)
endif()
endif()
endif()
# Determine whether CppUnit is installed.

3
NEWS
View File

@ -4,6 +4,9 @@
* 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.
* Several smaller bug fixes and performance improvements.
TagLib 1.11.1 (Oct 24, 2016)

View File

@ -1,5 +1,8 @@
/* config.h. Generated by cmake from config.h.cmake */
#ifndef TAGLIB_CONFIG_H
#define TAGLIB_CONFIG_H
/* Defined if required for large files support */
#cmakedefine _LARGE_FILES ${_LARGE_FILES}
#cmakedefine _LARGEFILE_SOURCE ${_LARGEFILE_SOURCE}
@ -15,7 +18,6 @@
/* Defined if your compiler supports some atomic operations */
#cmakedefine HAVE_STD_ATOMIC 1
#cmakedefine HAVE_BOOST_ATOMIC 1
#cmakedefine HAVE_GCC_ATOMIC 1
#cmakedefine HAVE_MAC_ATOMIC 1
#cmakedefine HAVE_WIN_ATOMIC 1
@ -34,10 +36,10 @@
/* Defined if zlib is installed */
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_BOOST_ZLIB 1
/* Indicates whether debug messages are shown even in release mode */
#cmakedefine TRACE_IN_RELEASE 1
#cmakedefine TESTS_DIR "@TESTS_DIR@"
#endif

View File

@ -35,7 +35,7 @@ elseif(HAVE_ZLIB_SOURCE)
include_directories(${ZLIB_SOURCE})
endif()
if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC OR HAVE_BOOST_ZLIB)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIR})
endif()
@ -377,18 +377,10 @@ set(tag_LIB_SRCS
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
if(ZLIB_FOUND)
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
target_link_libraries(tag ${ZLIB_LIBRARIES})
endif()
if(HAVE_BOOST_ATOMIC)
target_link_libraries(tag ${Boost_ATOMIC_LIBRARY})
endif()
if(HAVE_BOOST_ZLIB)
target_link_libraries(tag ${Boost_IOSTREAMS_LIBRARY} ${Boost_ZLIB_LIBRARY})
endif()
set_target_properties(tag PROPERTIES
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
@ -398,7 +390,13 @@ set_target_properties(tag PROPERTIES
PUBLIC_HEADER "${tag_HDRS}"
)
if(BUILD_FRAMEWORK)
set_target_properties(tag PROPERTIES FRAMEWORK TRUE)
unset(INSTALL_NAME_DIR)
set_target_properties(tag PROPERTIES
FRAMEWORK TRUE
MACOSX_RPATH 1
VERSION "A"
SOVERSION "A"
)
endif()
install(TARGETS tag

View File

@ -228,7 +228,7 @@ void APE::Tag::setGenre(const String &s)
void APE::Tag::setYear(unsigned int i)
{
if(i <= 0)
if(i == 0)
removeItem("YEAR");
else
addValue("YEAR", String::number(i), true);
@ -236,7 +236,7 @@ void APE::Tag::setYear(unsigned int i)
void APE::Tag::setTrack(unsigned int i)
{
if(i <= 0)
if(i == 0)
removeItem("TRACK");
else
addValue("TRACK", String::number(i), true);

View File

@ -112,7 +112,7 @@ namespace TagLib
/*!
* Copies the contents of \a other into this item.
*/
ASF::Attribute &operator=(const Attribute &other);
Attribute &operator=(const Attribute &other);
/*!
* Exchanges the content of the Attribute by the content of \a other.

View File

@ -153,8 +153,8 @@ bool FLAC::File::save()
}
// Create new vorbis comments
Tag::duplicate(&d->tag, xiphComment(true), false);
if(!hasXiphComment())
Tag::duplicate(&d->tag, xiphComment(true), false);
d->xiphCommentData = xiphComment()->render(false);

View File

@ -1028,10 +1028,10 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props)
if(reverseKeyMap.contains(it->first)) {
String name = reverseKeyMap[it->first];
if((it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") && !it->second.isEmpty()) {
int first = 0, second = 0;
StringList parts = StringList::split(it->second.front(), "/");
if(!parts.isEmpty()) {
first = parts[0].toInt();
int first = parts[0].toInt();
int second = 0;
if(parts.size() > 1) {
second = parts[1].toInt();
}

View File

@ -36,7 +36,9 @@ class TableOfContentsFrame::TableOfContentsFramePrivate
{
public:
TableOfContentsFramePrivate() :
tagHeader(0)
tagHeader(0),
isTopLevel(false),
isOrdered(false)
{
embeddedFrameList.setAutoDelete(true);
}

View File

@ -80,6 +80,7 @@ class ID3v2::Tag::TagPrivate
{
public:
TagPrivate() :
factory(0),
file(0),
tagOffset(0),
extendedHeader(0),
@ -375,7 +376,7 @@ void ID3v2::Tag::setGenre(const String &s)
void ID3v2::Tag::setYear(unsigned int i)
{
if(i <= 0) {
if(i == 0) {
removeFrames("TDRC");
return;
}
@ -384,7 +385,7 @@ void ID3v2::Tag::setYear(unsigned int i)
void ID3v2::Tag::setTrack(unsigned int i)
{
if(i <= 0) {
if(i == 0) {
removeFrames("TRCK");
return;
}

View File

@ -253,7 +253,7 @@ void Ogg::File::writePacket(unsigned int i, const ByteVector &packet)
ByteVectorList packets = firstPage->packets();
packets[i - firstPage->firstPacketIndex()] = packet;
if(firstPage != lastPage && lastPage->packetCount() > 2) {
if(firstPage != lastPage && lastPage->packetCount() > 1) {
ByteVectorList lastPagePackets = lastPage->packets();
lastPagePackets.erase(lastPagePackets.begin());
packets.append(lastPagePackets);

View File

@ -208,15 +208,15 @@ List<Ogg::Page *> Ogg::Page::paginate(const ByteVectorList &packets,
static const unsigned int SplitSize = 32 * 255;
// Force repagination if the packets are too large for a page.
// Force repagination if the segment table will exceed the size limit.
if(strategy != Repaginate) {
size_t totalSize = packets.size();
size_t tableSize = 0;
for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it)
totalSize += it->size();
tableSize += it->size() / 255 + 1;
if(totalSize > 255 * 255)
if(tableSize > 255)
strategy = Repaginate;
}

View File

@ -271,10 +271,14 @@ bool Ogg::XiphComment::checkKey(const String &key)
{
if(key.size() < 1)
return false;
for(String::ConstIterator it = key.begin(); it != key.end(); it++)
// forbid non-printable, non-ascii, '=' (#61) and '~' (#126)
if (*it < 32 || *it >= 128 || *it == 61 || *it == 126)
// A key may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
for(String::ConstIterator it = key.begin(); it != key.end(); it++) {
if(*it < 0x20 || *it > 0x7D || *it == 0x3D)
return false;
}
return true;
}
@ -285,11 +289,18 @@ String Ogg::XiphComment::vendorID() const
void Ogg::XiphComment::addField(const String &key, const String &value, bool replace)
{
if(!checkKey(key)) {
debug("Ogg::XiphComment::addField() - Invalid key. Field not added.");
return;
}
const String upperKey = key.upper();
if(replace)
removeFields(key.upper());
removeFields(upperKey);
if(!key.isEmpty() && !value.isEmpty())
d->fieldListMap[key.upper()].append(value);
d->fieldListMap[upperKey].append(value);
}
void Ogg::XiphComment::removeFields(const String &key)
@ -444,86 +455,69 @@ void Ogg::XiphComment::parse(const ByteVector &data)
const unsigned int commentLength = data.toUInt32LE(pos);
pos += 4;
ByteVector entry = data.mid(pos, commentLength);
const ByteVector entry = data.mid(pos, commentLength);
pos += commentLength;
// Don't go past data end
if(pos > data.size())
break;
// Handle Pictures separately
if(entry.startsWith("METADATA_BLOCK_PICTURE=")) {
// We need base64 encoded data including padding
if((entry.size() - 23) > 3 && ((entry.size() - 23) % 4) == 0) {
// Decode base64 picture data
ByteVector picturedata = ByteVector::fromBase64(entry.mid(23));
if(picturedata.size()) {
// Decode Flac Picture
FLAC::Picture * picture = new FLAC::Picture();
if(picture->parse(picturedata)) {
d->pictureList.append(picture);
// continue to next field
continue;
}
else {
delete picture;
debug("Failed to decode FlacPicture block");
}
}
else {
debug("Failed to decode base64 encoded data");
}
}
else {
debug("Invalid base64 encoded data");
}
}
// Handle old picture standard
if(entry.startsWith("COVERART=")) {
if((entry.size() - 9) > 3 && ((entry.size() - 9) % 4) == 0) {
// Decode base64 picture data
ByteVector picturedata = ByteVector::fromBase64(entry.mid(9));
if (picturedata.size()) {
// Assume it's some type of image file
FLAC::Picture * picture = new FLAC::Picture();
picture->setData(picturedata);
picture->setMimeType("image/");
picture->setType(FLAC::Picture::Other);
d->pictureList.append(picture);
// continue to next field
continue;
}
else {
debug("Failed to decode base64 encoded data");
}
}
else {
debug("Invalid base64 encoded data");
}
}
// Check for field separator
size_t sep = entry.find('=');
if(sep == ByteVector::npos()) {
debug("Discarding invalid comment field.");
const size_t sep = entry.find('=');
if(sep == 0 || sep == ByteVector::npos()) {
debug("Ogg::XiphComment::parse() - Discarding a field. Separator not found.");
continue;
}
// Parse key and value
String key = String(entry.mid(0, sep), String::UTF8);
String value = String(entry.mid(sep + 1), String::UTF8);
addField(key, value, false);
// Parse the key
const String key = String(entry.mid(0, sep), String::UTF8).upper();
if(!checkKey(key)) {
debug("Ogg::XiphComment::parse() - Discarding a field. Invalid key.");
continue;
}
if(key == "METADATA_BLOCK_PICTURE" || key == "COVERART") {
// Handle Pictures separately
const ByteVector picturedata = ByteVector::fromBase64(entry.mid(sep + 1));
if(picturedata.isEmpty()) {
debug("Ogg::XiphComment::parse() - Discarding a field. Invalid base64 data");
continue;
}
if(key[0] == L'M') {
// Decode FLAC Picture
FLAC::Picture * picture = new FLAC::Picture();
if(picture->parse(picturedata)) {
d->pictureList.append(picture);
}
else {
delete picture;
debug("Ogg::XiphComment::parse() - Failed to decode FLAC Picture block");
}
}
else {
// Assume it's some type of image file
FLAC::Picture * picture = new FLAC::Picture();
picture->setData(picturedata);
picture->setMimeType("image/");
picture->setType(FLAC::Picture::Other);
d->pictureList.append(picture);
}
}
else {
// Parse the text
addField(key, String(entry.mid(sep + 1), String::UTF8), false);
}
}
}

View File

@ -0,0 +1,11 @@
/* taglib_config.h. Generated by cmake from taglib_config.h.cmake */
#ifndef TAGLIB_TAGLIB_CONFIG_H
#define TAGLIB_TAGLIB_CONFIG_H
/* These values are no longer used. This file is present only for compatibility reasons. */
#define TAGLIB_WITH_ASF 1
#define TAGLIB_WITH_MP4 1
#endif

View File

@ -29,7 +29,6 @@
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstddef>
#include <tstring.h>
#include <tdebug.h>
@ -164,7 +163,7 @@ TFloat toFloat(const ByteVector &v, size_t offset)
} tmp;
::memcpy(&tmp, v.data() + offset, sizeof(TInt));
if(ENDIAN != Utils::floatByteOrder())
if(ENDIAN != Utils::systemByteOrder())
tmp.i = Utils::byteSwap(tmp.i);
return tmp.f;
@ -179,7 +178,7 @@ ByteVector fromFloat(TFloat value)
} tmp;
tmp.f = value;
if(ENDIAN != Utils::floatByteOrder())
if(ENDIAN != Utils::systemByteOrder())
tmp.i = Utils::byteSwap(tmp.i);
return ByteVector(reinterpret_cast<char *>(&tmp), sizeof(TInt));
@ -482,46 +481,60 @@ ByteVector &ByteVector::replace(char oldByte, char newByte)
ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &with)
{
// TODO: This takes O(n!) time in the worst case. Rewrite it to run in O(n) time.
if(pattern.size() == 0 || pattern.size() > size())
return *this;
if(pattern.size() == 1 && with.size() == 1)
return replace(pattern[0], with[0]);
const size_t withSize = with.size();
const size_t patternSize = pattern.size();
const ptrdiff_t diff = withSize - patternSize;
// Check if there is at least one occurrence of the pattern.
size_t offset = 0;
while (true) {
offset = find(pattern, offset);
if(offset == npos())
break;
size_t offset = find(pattern, 0);
if(offset == ByteVector::npos())
return *this;
if(pattern.size() == with.size()) {
// We think this case might be common enough to optimize it.
detach();
do
{
::memcpy(data() + offset, with.data(), with.size());
offset = find(pattern, offset + pattern.size());
} while(offset != ByteVector::npos());
}
else {
if(diff < 0) {
::memmove(
data() + offset + withSize,
data() + offset + patternSize,
size() - offset - patternSize);
resize(size() + diff);
}
else if(diff > 0) {
resize(size() + diff);
::memmove(
data() + offset + withSize,
data() + offset + patternSize,
size() - diff - offset - patternSize);
// Loop once to calculate the result size.
size_t dstSize = size();
do
{
dstSize += with.size() - pattern.size();
offset = find(pattern, offset + pattern.size());
} while(offset != ByteVector::npos());
// Loop again to copy modified data to the new vector.
ByteVector dst(dstSize);
size_t dstOffset = 0;
offset = 0;
while(true) {
const size_t next = find(pattern, offset);
if(next == ByteVector::npos()) {
::memcpy(dst.data() + dstOffset, data() + offset, size() - offset);
break;
}
::memcpy(dst.data() + dstOffset, data() + offset, next - offset);
dstOffset += next - offset;
::memcpy(dst.data() + dstOffset, with.data(), with.size());
dstOffset += with.size();
offset = next + pattern.size();
}
::memcpy(data() + offset, with.data(), with.size());
offset += withSize;
if(offset > size() - patternSize)
break;
swap(dst);
}
return *this;

View File

@ -31,14 +31,9 @@
#if defined(HAVE_STD_ATOMIC)
# include <atomic>
# define ATOMIC_INT std::atomic<int>
# define ATOMIC_INC(x) x.fetch_add(1)
# define ATOMIC_DEC(x) (x.fetch_sub(1) - 1)
#elif defined(HAVE_BOOST_ATOMIC)
# include <boost/atomic.hpp>
# define ATOMIC_INT boost::atomic<int>
# define ATOMIC_INC(x) x.fetch_add(1)
# define ATOMIC_DEC(x) (x.fetch_sub(1) - 1)
# define ATOMIC_INT std::atomic_int
# define ATOMIC_INC(x) (++x)
# define ATOMIC_DEC(x) (--x)
#elif defined(HAVE_GCC_ATOMIC)
# define ATOMIC_INT int
# define ATOMIC_INC(x) ::__sync_add_and_fetch(&x, 1)

View File

@ -88,7 +88,7 @@ namespace
#ifdef _WIN32
len = ::MultiByteToWideChar(
CP_UTF8, 0, src, static_cast<int>(srcLength), dst, static_cast<int>(dstLength));
CP_UTF8, MB_ERR_INVALID_CHARS, src, static_cast<int>(srcLength), dst, static_cast<int>(dstLength));
#else
@ -448,7 +448,10 @@ bool String::startsWith(const String &s) const
String String::substr(size_t position, size_t length) const
{
return String(d->data->substr(position, length));
if(position == 0 && length >= size())
return *this;
else
return String(d->data->substr(position, length));
}
String &String::append(const String &s)
@ -501,7 +504,7 @@ 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(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it)
*p++ = static_cast<char>(*it);
return v;
@ -529,7 +532,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(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
*p++ = static_cast<char>(*it & 0xff);
*p++ = static_cast<char>(*it >> 8);
}
@ -541,7 +544,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(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
*p++ = static_cast<char>(*it >> 8);
*p++ = static_cast<char>(*it & 0xff);
}
@ -553,7 +556,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(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
*p++ = static_cast<char>(*it & 0xff);
*p++ = static_cast<char>(*it >> 8);
}
@ -598,7 +601,7 @@ String String::stripWhiteSpace() const
bool String::isLatin1() const
{
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); it++) {
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
if(*it >= 256)
return false;
}
@ -607,7 +610,7 @@ bool String::isLatin1() const
bool String::isAscii() const
{
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); it++) {
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); ++it) {
if(*it >= 128)
return false;
}

View File

@ -222,7 +222,7 @@ namespace TagLib
}
/*!
* Returns the integer byte order of the system.
* Returns the byte order of the system.
*/
inline ByteOrder systemByteOrder()
{
@ -237,26 +237,6 @@ namespace TagLib
else
return BigEndian;
}
/*!
* Returns the IEEE754 byte order of the system.
*/
inline ByteOrder floatByteOrder()
{
union {
double d;
char c;
} u;
// 1.0 is stored in memory like 0x3FF0000000000000 in canonical form.
// So the first byte is zero if little endian.
u.d = 1.0;
if(u.c == 0)
return LittleEndian;
else
return BigEndian;
}
}
}
}

View File

@ -27,23 +27,19 @@
# include <config.h>
#endif
#if defined(HAVE_ZLIB)
#ifdef HAVE_ZLIB
# include <zlib.h>
#elif defined(HAVE_BOOST_ZLIB)
# include <boost/iostreams/filtering_streambuf.hpp>
# include <boost/iostreams/filter/zlib.hpp>
# include <tstring.h>
# include <tdebug.h>
#endif
#include <tstring.h>
#include <tdebug.h>
#include "tzlib.h"
using namespace TagLib;
bool zlib::isAvailable()
{
#if defined(HAVE_ZLIB) || defined(HAVE_BOOST_ZLIB)
#ifdef HAVE_ZLIB
return true;
@ -56,7 +52,7 @@ bool zlib::isAvailable()
ByteVector zlib::decompress(const ByteVector &data)
{
#if defined(HAVE_ZLIB)
#ifdef HAVE_ZLIB
z_stream stream = {};
@ -102,38 +98,6 @@ ByteVector zlib::decompress(const ByteVector &data)
return outData;
#elif defined(HAVE_BOOST_ZLIB)
using namespace boost::iostreams;
struct : public sink
{
ByteVector data;
typedef char char_type;
typedef sink_tag category;
std::streamsize write(char const* s, std::streamsize n)
{
const size_t originalSize = data.size();
data.resize(static_cast<size_t>(originalSize + n));
::memcpy(data.data() + originalSize, s, static_cast<size_t>(n));
return n;
}
} sink;
try {
zlib_decompressor().write(sink, data.data(), data.size());
}
catch(const zlib_error &) {
debug("zlib::decompress() - Error reading compressed stream.");
return ByteVector();
}
return sink.data;
#else
return ByteVector();

View File

@ -590,9 +590,9 @@ void XM::File::read(bool)
unsigned int count = 4 + instrument.read(*this, instrumentHeaderSize - 4U);
READ_ASSERT(count == std::min(instrumentHeaderSize, instrument.size() + 4));
unsigned int sampleHeaderSize = 0;
long offset = 0;
if(sampleCount > 0) {
unsigned int sampleHeaderSize = 0;
sumSampleCount += sampleCount;
// wouldn't know which header size to assume otherwise:
READ_ASSERT(instrumentHeaderSize >= count + 4 && readU32L(sampleHeaderSize));

Binary file not shown.

View File

@ -46,6 +46,7 @@ class TestByteVector : public CppUnit::TestFixture
CPPUNIT_TEST(testIntegerConversion);
CPPUNIT_TEST(testFloatingPointConversion);
CPPUNIT_TEST(testReplace);
CPPUNIT_TEST(testReplaceAndDetach);
CPPUNIT_TEST(testIterator);
CPPUNIT_TEST(testResize);
CPPUNIT_TEST(testAppend1);
@ -312,6 +313,45 @@ public:
}
}
void testReplaceAndDetach()
{
{
ByteVector a("abcdabf");
ByteVector b = a;
a.replace(ByteVector("a"), ByteVector("x"));
CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a);
CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b);
}
{
ByteVector a("abcdabf");
ByteVector b = a;
a.replace('a', 'x');
CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a);
CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b);
}
{
ByteVector a("abcdabf");
ByteVector b = a;
a.replace(ByteVector("ab"), ByteVector("xy"));
CPPUNIT_ASSERT_EQUAL(ByteVector("xycdxyf"), a);
CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b);
}
{
ByteVector a("abcdabf");
ByteVector b = a;
a.replace(ByteVector("a"), ByteVector("<a>"));
CPPUNIT_ASSERT_EQUAL(ByteVector("<a>bcd<a>bf"), a);
CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), b);
}
{
ByteVector a("ab<c>dab<c>");
ByteVector b = a;
a.replace(ByteVector("<c>"), ByteVector("c"));
CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabc"), a);
CPPUNIT_ASSERT_EQUAL(ByteVector("ab<c>dab<c>"), b);
}
}
void testIterator()
{
ByteVector v1("taglib");

View File

@ -62,6 +62,7 @@ class TestFLAC : public CppUnit::TestFixture
CPPUNIT_TEST(testUpdateID3v2);
CPPUNIT_TEST(testEmptyID3v2);
CPPUNIT_TEST(testStripTags);
CPPUNIT_TEST(testRemoveXiphField);
CPPUNIT_TEST_SUITE_END();
public:
@ -493,6 +494,28 @@ public:
}
}
void testRemoveXiphField()
{
ScopedFileCopy copy("silence-44-s", ".flac");
{
FLAC::File f(copy.fileName().c_str());
f.xiphComment(true)->setTitle("XiphComment Title");
f.ID3v2Tag(true)->setTitle("ID3v2 Title");
f.save();
}
{
FLAC::File f(copy.fileName().c_str());
CPPUNIT_ASSERT_EQUAL(String("XiphComment Title"), f.xiphComment()->title());
f.xiphComment()->removeFields("TITLE");
f.save();
}
{
FLAC::File f(copy.fileName().c_str());
CPPUNIT_ASSERT_EQUAL(String(), f.xiphComment()->title());
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC);

View File

@ -32,12 +32,13 @@ using namespace TagLib;
class TestList : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestList);
CPPUNIT_TEST(testList);
CPPUNIT_TEST(testAppend);
CPPUNIT_TEST(testDetach);
CPPUNIT_TEST_SUITE_END();
public:
void testList()
void testAppend()
{
List<int> l1;
List<int> l2;
@ -51,14 +52,25 @@ public:
l3.append(2);
l3.append(3);
l3.append(4);
CPPUNIT_ASSERT_EQUAL((size_t)4, l1.size());
CPPUNIT_ASSERT(l1 == l3);
List<int> l4 = l1;
List<int>::Iterator it = l4.find(3);
*it = 33;
CPPUNIT_ASSERT_EQUAL(l1[2], 3);
CPPUNIT_ASSERT_EQUAL(l4[2], 33);
}
void testDetach()
{
List<int> l1;
l1.append(1);
l1.append(2);
l1.append(3);
l1.append(4);
List<int> l2 = l1;
List<int>::Iterator it = l2.find(3);
*it = 33;
CPPUNIT_ASSERT_EQUAL(3, l1[2]);
CPPUNIT_ASSERT_EQUAL(33, l2[2]);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestList);

View File

@ -34,6 +34,7 @@ class TestMap : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestMap);
CPPUNIT_TEST(testInsert);
CPPUNIT_TEST(testDetach);
CPPUNIT_TEST_SUITE_END();
public:
@ -42,19 +43,28 @@ public:
{
Map<String, int> m1;
m1.insert("foo", 3);
m1.insert("bar", 5);
CPPUNIT_ASSERT_EQUAL((size_t)2, m1.size());
CPPUNIT_ASSERT_EQUAL(3, m1["foo"]);
CPPUNIT_ASSERT_EQUAL(5, m1["bar"]);
m1.insert("foo", 7);
CPPUNIT_ASSERT_EQUAL((size_t)2, m1.size());
CPPUNIT_ASSERT_EQUAL(7, m1["foo"]);
CPPUNIT_ASSERT_EQUAL(5, m1["bar"]);
}
m1.insert("alice", 5);
m1.insert("bob", 9);
void testDetach()
{
Map<String, int> m1;
m1.insert("alice", 5);
m1.insert("bob", 9);
m1.insert("carol", 11);
Map<String, int> m2 = m1;
Map<String, int>::Iterator it = m2.find("bob");
(*it).second = 99;
CPPUNIT_ASSERT_EQUAL(m1["bob"], 9);
CPPUNIT_ASSERT_EQUAL(m2["bob"], 99);
CPPUNIT_ASSERT_EQUAL(9, m1["bob"]);
CPPUNIT_ASSERT_EQUAL(99, m2["bob"]);
}
};

View File

@ -42,7 +42,8 @@ class TestOGG : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestOGG);
CPPUNIT_TEST(testSimple);
CPPUNIT_TEST(testSplitPackets);
CPPUNIT_TEST(testSplitPackets1);
CPPUNIT_TEST(testSplitPackets2);
CPPUNIT_TEST(testDictInterface1);
CPPUNIT_TEST(testDictInterface2);
CPPUNIT_TEST(testAudioProperties);
@ -67,7 +68,7 @@ public:
}
}
void testSplitPackets()
void testSplitPackets1()
{
ScopedFileCopy copy("empty", ".ogg");
string newname = copy.fileName();
@ -110,6 +111,33 @@ public:
}
}
void testSplitPackets2()
{
ScopedFileCopy copy("empty", ".ogg");
string newname = copy.fileName();
const String text = longText(60890, true);
{
Ogg::Vorbis::File f(newname.c_str());
f.tag()->setTitle(text);
f.save();
}
{
Ogg::Vorbis::File f(newname.c_str());
CPPUNIT_ASSERT(f.isValid());
CPPUNIT_ASSERT_EQUAL(text, f.tag()->title());
f.tag()->setTitle("ABCDE");
f.save();
}
{
Ogg::Vorbis::File f(newname.c_str());
CPPUNIT_ASSERT(f.isValid());
CPPUNIT_ASSERT_EQUAL(String("ABCDE"), f.tag()->title());
}
}
void testDictInterface1()
{
ScopedFileCopy copy("empty", ".ogg");

View File

@ -50,6 +50,7 @@ class TestString : public CppUnit::TestFixture
CPPUNIT_TEST(testEncodeNonLatin1);
CPPUNIT_TEST(testEncodeEmpty);
CPPUNIT_TEST(testIterator);
CPPUNIT_TEST(testRedundantUTF8);
CPPUNIT_TEST_SUITE_END();
public:
@ -109,6 +110,9 @@ public:
CPPUNIT_ASSERT(String(" foo ").stripWhiteSpace() == String("foo"));
CPPUNIT_ASSERT(String("foo ").stripWhiteSpace() == String("foo"));
CPPUNIT_ASSERT(String(" foo").stripWhiteSpace() == String("foo"));
CPPUNIT_ASSERT(String("foo").stripWhiteSpace() == String("foo"));
CPPUNIT_ASSERT(String("f o o").stripWhiteSpace() == String("f o o"));
CPPUNIT_ASSERT(String(" f o o ").stripWhiteSpace() == String("f o o"));
CPPUNIT_ASSERT(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0);
CPPUNIT_ASSERT(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0);
@ -265,6 +269,8 @@ public:
CPPUNIT_ASSERT_EQUAL(String("01"), String("0123456").substr(0, 2));
CPPUNIT_ASSERT_EQUAL(String("12"), String("0123456").substr(1, 2));
CPPUNIT_ASSERT_EQUAL(String("123456"), String("0123456").substr(1, 200));
CPPUNIT_ASSERT_EQUAL(String("0123456"), String("0123456").substr(0, 7));
CPPUNIT_ASSERT_EQUAL(String("0123456"), String("0123456").substr(0, 200));
}
void testNewline()
@ -332,6 +338,15 @@ public:
CPPUNIT_ASSERT_EQUAL(L'i', *it1);
CPPUNIT_ASSERT_EQUAL(L'I', *it2);
}
void testRedundantUTF8()
{
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_TEST_SUITE_REGISTRATION(TestString);

View File

@ -42,10 +42,12 @@ class TestXiphComment : public CppUnit::TestFixture
CPPUNIT_TEST(testSetYear);
CPPUNIT_TEST(testTrack);
CPPUNIT_TEST(testSetTrack);
CPPUNIT_TEST(testInvalidKeys);
CPPUNIT_TEST(testInvalidKeys1);
CPPUNIT_TEST(testInvalidKeys2);
CPPUNIT_TEST(testClearComment);
CPPUNIT_TEST(testRemoveFields);
CPPUNIT_TEST(testPicture);
CPPUNIT_TEST(testLowercaseFields);
CPPUNIT_TEST_SUITE_END();
public:
@ -90,19 +92,32 @@ public:
CPPUNIT_ASSERT_EQUAL(String("3"), cmt.fieldListMap()["TRACKNUMBER"].front());
}
void testInvalidKeys()
void testInvalidKeys1()
{
PropertyMap map;
map[""] = String("invalid key: empty string");
map["A=B"] = String("invalid key: contains '='");
map["A~B"] = String("invalid key: contains '~'");
map["A\x7F" "B"] = String("invalid key: contains '\x7F'");
map[L"A\x3456" "B"] = String("invalid key: Unicode");
Ogg::XiphComment cmt;
PropertyMap unsuccessful = cmt.setProperties(map);
CPPUNIT_ASSERT_EQUAL((size_t)3, unsuccessful.size());
CPPUNIT_ASSERT_EQUAL((size_t)5, unsuccessful.size());
CPPUNIT_ASSERT(cmt.properties().isEmpty());
}
void testInvalidKeys2()
{
Ogg::XiphComment cmt;
cmt.addField("", "invalid key: empty string");
cmt.addField("A=B", "invalid key: contains '='");
cmt.addField("A~B", "invalid key: contains '~'");
cmt.addField("A\x7F" "B", "invalid key: contains '\x7F'");
cmt.addField(L"A\x3456" "B", "invalid key: Unicode");
CPPUNIT_ASSERT_EQUAL(0U, cmt.fieldCount());
}
void testClearComment()
{
ScopedFileCopy copy("empty", ".ogg");
@ -178,6 +193,23 @@ public:
}
}
void testLowercaseFields()
{
const ScopedFileCopy copy("lowercase-fields", ".ogg");
{
Ogg::Vorbis::File f(copy.fileName().c_str());
List<FLAC::Picture *> lst = f.tag()->pictureList();
CPPUNIT_ASSERT_EQUAL(String("TEST TITLE"), f.tag()->title());
CPPUNIT_ASSERT_EQUAL(String("TEST ARTIST"), f.tag()->artist());
CPPUNIT_ASSERT_EQUAL((size_t)1, lst.size());
f.save();
}
{
Ogg::Vorbis::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.find("METADATA_BLOCK_PICTURE") > 0);
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestXiphComment);