mirror of
https://github.com/taglib/taglib.git
synced 2025-06-04 01:28:21 -04:00
Merge branch 'master' into merge-master-to-taglib2
Conflicts: taglib/riff/wav/infotag.cpp taglib/toolkit/trefcounter.h taglib/toolkit/tstring.cpp taglib/toolkit/tstring.h taglib/xm/xmfile.cpp tests/test_string.cpp
This commit is contained in:
commit
bd84c8928a
2
INSTALL
2
INSTALL
@ -5,7 +5,7 @@ TagLib uses the CMake build system. As a user, you will most likely want to
|
||||
build TagLib in release mode and install it into a system-wide location.
|
||||
This can be done using the following commands:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_RELEASE_TYPE=Release .
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release .
|
||||
make
|
||||
sudo make install
|
||||
|
||||
|
@ -61,7 +61,7 @@ install(TARGETS tag_c
|
||||
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
|
||||
)
|
||||
|
||||
if(NOT WIN32 AND NOT BUILD_FRAMEWORK)
|
||||
if(NOT BUILD_FRAMEWORK)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
|
||||
endif()
|
||||
|
@ -1,36 +1,36 @@
|
||||
@echo off
|
||||
goto beginning
|
||||
*
|
||||
* It is what it is, you can do with it as you please.
|
||||
*
|
||||
* Just don't blame me if it teaches your computer to smoke!
|
||||
*
|
||||
* -Enjoy
|
||||
* fh :)_~
|
||||
*
|
||||
:beginning
|
||||
if /i "%1#" == "--libs#" goto doit
|
||||
if /i "%1#" == "--cflags#" goto doit
|
||||
if /i "%1#" == "--version#" goto doit
|
||||
if /i "%1#" == "--prefix#" goto doit
|
||||
|
||||
echo "usage: %0 [OPTIONS]"
|
||||
echo [--libs]
|
||||
echo [--cflags]
|
||||
echo [--version]
|
||||
echo [--prefix]
|
||||
goto theend
|
||||
|
||||
*
|
||||
* NOTE: Windows does not assume libraries are prefixed with 'lib'.
|
||||
* NOTE: If '-llibtag' is the last element, it is easily appended in the users installation/makefile process
|
||||
* to allow for static, shared or debug builds.
|
||||
* It would be preferable if the top level CMakeLists.txt provided the library name during config. ??
|
||||
:doit
|
||||
if /i "%1#" == "--libs#" echo -L${LIB_INSTALL_DIR} -llibtag
|
||||
if /i "%1#" == "--cflags#" echo -I${INCLUDE_INSTALL_DIR}/taglib
|
||||
if /i "%1#" == "--version#" echo ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}
|
||||
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}
|
||||
|
||||
:theend
|
||||
|
||||
@echo off
|
||||
goto beginning
|
||||
*
|
||||
* It is what it is, you can do with it as you please.
|
||||
*
|
||||
* Just don't blame me if it teaches your computer to smoke!
|
||||
*
|
||||
* -Enjoy
|
||||
* fh :)_~
|
||||
*
|
||||
:beginning
|
||||
if /i "%1#" == "--libs#" goto doit
|
||||
if /i "%1#" == "--cflags#" goto doit
|
||||
if /i "%1#" == "--version#" goto doit
|
||||
if /i "%1#" == "--prefix#" goto doit
|
||||
|
||||
echo "usage: %0 [OPTIONS]"
|
||||
echo [--libs]
|
||||
echo [--cflags]
|
||||
echo [--version]
|
||||
echo [--prefix]
|
||||
goto theend
|
||||
|
||||
*
|
||||
* NOTE: Windows does not assume libraries are prefixed with 'lib'.
|
||||
* NOTE: If '-llibtag' is the last element, it is easily appended in the users installation/makefile process
|
||||
* to allow for static, shared or debug builds.
|
||||
* It would be preferable if the top level CMakeLists.txt provided the library name during config. ??
|
||||
:doit
|
||||
if /i "%1#" == "--libs#" echo -L${LIB_INSTALL_DIR} -llibtag
|
||||
if /i "%1#" == "--cflags#" echo -I${INCLUDE_INSTALL_DIR}/taglib
|
||||
if /i "%1#" == "--version#" echo ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}
|
||||
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}
|
||||
|
||||
:theend
|
||||
|
||||
|
@ -234,7 +234,7 @@ namespace TagLib {
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
|
||||
//! An ID3v2 custom text identification frame implementationx
|
||||
//! An ID3v2 custom text identification frame implementation
|
||||
|
||||
class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ using namespace RIFF::Info;
|
||||
class RIFF::Info::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate()
|
||||
TagPrivate()
|
||||
{}
|
||||
|
||||
FieldListMap fieldListMap;
|
||||
@ -72,14 +72,14 @@ ByteVector RIFF::Info::StringHandler::render(const String &s) const
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RIFF::Info::Tag::Tag(const ByteVector &data)
|
||||
RIFF::Info::Tag::Tag(const ByteVector &data)
|
||||
: TagLib::Tag()
|
||||
, d(new TagPrivate())
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
RIFF::Info::Tag::Tag()
|
||||
RIFF::Info::Tag::Tag()
|
||||
: TagLib::Tag()
|
||||
, d(new TagPrivate())
|
||||
{
|
||||
@ -215,7 +215,7 @@ ByteVector RIFF::Info::Tag::render() const
|
||||
data.append(it->first);
|
||||
data.append(ByteVector::fromUInt32LE(text.size() + 1));
|
||||
data.append(text);
|
||||
|
||||
|
||||
do {
|
||||
data.append('\0');
|
||||
} while(data.size() & 1);
|
||||
|
@ -141,13 +141,13 @@ namespace
|
||||
debug("String::copyFromUTF8() - Unicode conversion error.");
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class String::StringPrivate
|
||||
class String::StringPrivate
|
||||
{
|
||||
public:
|
||||
StringPrivate()
|
||||
@ -155,13 +155,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
StringPrivate(size_t n, wchar_t c)
|
||||
: data(new std::wstring(n, c))
|
||||
StringPrivate(size_t n, wchar_t c)
|
||||
: data(new std::wstring(n, c))
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Stores string in UTF-16. The byte order depends on the CPU endian.
|
||||
* Stores string in UTF-16. The byte order depends on the CPU endian.
|
||||
*/
|
||||
SHARED_PTR<std::wstring> data;
|
||||
|
||||
@ -178,12 +178,12 @@ const size_t String::npos = std::wstring::npos;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
String::String()
|
||||
String::String()
|
||||
: d(new StringPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
String::String(const String &s)
|
||||
String::String(const String &s)
|
||||
: d(new StringPrivate(*s.d))
|
||||
{
|
||||
}
|
||||
@ -192,9 +192,9 @@ String::String(const std::string &s, Type t)
|
||||
: d(new StringPrivate())
|
||||
{
|
||||
if(t == Latin1)
|
||||
copyFromLatin1(&s[0], s.length());
|
||||
copyFromLatin1(s.c_str(), s.length());
|
||||
else if(t == String::UTF8)
|
||||
copyFromUTF8(&s[0], s.length());
|
||||
copyFromUTF8(s.c_str(), s.length());
|
||||
else {
|
||||
debug("String::String() -- A std::string should not contain UTF16.");
|
||||
}
|
||||
@ -256,11 +256,11 @@ String::String(const ByteVector &v, Type t)
|
||||
if(v.isEmpty())
|
||||
return;
|
||||
|
||||
if(t == Latin1)
|
||||
if(t == Latin1)
|
||||
copyFromLatin1(v.data(), v.size());
|
||||
else if(t == UTF8)
|
||||
else if(t == UTF8)
|
||||
copyFromUTF8(v.data(), v.size());
|
||||
else
|
||||
else
|
||||
copyFromUTF16(v.data(), v.size(), t);
|
||||
|
||||
// If we hit a null in the ByteVector, shrink the string again.
|
||||
@ -276,25 +276,8 @@ String::~String()
|
||||
|
||||
std::string String::to8Bit(bool unicode) const
|
||||
{
|
||||
std::string s;
|
||||
|
||||
if(!unicode) {
|
||||
s.resize(d->data->size());
|
||||
|
||||
std::string::iterator targetIt = s.begin();
|
||||
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); it++) {
|
||||
*targetIt = static_cast<char>(*it);
|
||||
++targetIt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
s.resize(d->data->size() * 4 + 1);
|
||||
|
||||
UTF16toUTF8(&(*d->data)[0], d->data->size(), &s[0], s.size());
|
||||
s.resize(::strlen(s.c_str()));
|
||||
}
|
||||
|
||||
return s;
|
||||
const ByteVector v = data(unicode ? UTF8 : Latin1);
|
||||
return std::string(v.data(), v.size());
|
||||
}
|
||||
|
||||
const std::wstring &String::toWString() const
|
||||
@ -418,74 +401,78 @@ bool String::isNull() const
|
||||
|
||||
ByteVector String::data(Type t) const
|
||||
{
|
||||
switch(t)
|
||||
switch(t)
|
||||
{
|
||||
case Latin1:
|
||||
{
|
||||
ByteVector v(size(), 0);
|
||||
char *p = v.data();
|
||||
{
|
||||
ByteVector v(size(), 0);
|
||||
char *p = v.data();
|
||||
|
||||
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); it++)
|
||||
*p++ = static_cast<char>(*it);
|
||||
for(std::wstring::const_iterator it = d->data->begin(); it != d->data->end(); it++)
|
||||
*p++ = static_cast<char>(*it);
|
||||
|
||||
return v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
case UTF8:
|
||||
{
|
||||
ByteVector v(size() * 4 + 1, 0);
|
||||
if(!d->data->empty())
|
||||
{
|
||||
ByteVector v(size() * 4 + 1, 0);
|
||||
|
||||
UTF16toUTF8(&(*d->data)[0], d->data->size(), v.data(), v.size());
|
||||
v.resize(::strlen(v.data()));
|
||||
UTF16toUTF8(d->data->c_str(), d->data->size(), v.data(), v.size());
|
||||
v.resize(::strlen(v.data()));
|
||||
|
||||
return v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
else {
|
||||
return ByteVector::null;
|
||||
}
|
||||
case UTF16:
|
||||
{
|
||||
ByteVector v(2 + size() * 2, 0);
|
||||
char *p = v.data();
|
||||
{
|
||||
ByteVector v(2 + size() * 2, 0);
|
||||
char *p = v.data();
|
||||
|
||||
// Assume that if we're doing UTF16 and not UTF16BE that we want little
|
||||
// endian encoding. (Byte Order Mark)
|
||||
// Assume that if we're doing UTF16 and not UTF16BE that we want little
|
||||
// endian encoding. (Byte Order Mark)
|
||||
|
||||
*p++ = '\xff';
|
||||
*p++ = '\xfe';
|
||||
*p++ = '\xff';
|
||||
*p++ = '\xfe';
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
case UTF16BE:
|
||||
{
|
||||
ByteVector v(size() * 2, 0);
|
||||
char *p = v.data();
|
||||
{
|
||||
ByteVector v(size() * 2, 0);
|
||||
char *p = v.data();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
case UTF16LE:
|
||||
{
|
||||
ByteVector v(size() * 2, 0);
|
||||
char *p = v.data();
|
||||
{
|
||||
ByteVector v(size() * 2, 0);
|
||||
char *p = v.data();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
{
|
||||
debug("String::data() - Invalid Type value.");
|
||||
return ByteVector();
|
||||
}
|
||||
{
|
||||
debug("String::data() - Invalid Type value.");
|
||||
return ByteVector::null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,17 +704,19 @@ void String::copyFromUTF8(const char *s, size_t length)
|
||||
{
|
||||
d->data->resize(length);
|
||||
|
||||
UTF8toUTF16(s, length, &(*d->data)[0], d->data->size());
|
||||
d->data->resize(::wcslen(d->data->c_str()));
|
||||
if(length > 0) {
|
||||
UTF8toUTF16(s, length, &(*d->data)[0], d->data->size());
|
||||
d->data->resize(::wcslen(d->data->c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void String::copyFromUTF16(const wchar_t *s, size_t length, Type t)
|
||||
{
|
||||
bool swap;
|
||||
if(t == UTF16) {
|
||||
if(length >= 1 && s[0] == 0xfeff)
|
||||
if(length >= 1 && s[0] == 0xfeff)
|
||||
swap = false; // Same as CPU endian. No need to swap bytes.
|
||||
else if(length >= 1 && s[0] == 0xfffe)
|
||||
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.");
|
||||
@ -737,15 +726,18 @@ void String::copyFromUTF16(const wchar_t *s, size_t length, Type t)
|
||||
s++;
|
||||
length--;
|
||||
}
|
||||
else
|
||||
else
|
||||
swap = (t != WCharByteOrder);
|
||||
|
||||
d->data->resize(length);
|
||||
memcpy(&(*d->data)[0], s, length * sizeof(wchar_t));
|
||||
|
||||
if(swap) {
|
||||
for(size_t i = 0; i < length; ++i)
|
||||
(*d->data)[i] = Utils::byteSwap(static_cast<ushort>(s[i]));
|
||||
if(length > 0) {
|
||||
if(swap) {
|
||||
for(size_t i = 0; i < length; ++i)
|
||||
(*d->data)[i] = Utils::byteSwap(static_cast<ushort>(s[i]));
|
||||
}
|
||||
else {
|
||||
::memcpy(&(*d->data)[0], s, length * sizeof(wchar_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,9 +754,9 @@ void String::copyFromUTF16(const char *s, size_t length, Type t)
|
||||
ushort bom;
|
||||
::memcpy(&bom, s, 2);
|
||||
|
||||
if(bom == 0xfeff)
|
||||
if(bom == 0xfeff)
|
||||
swap = false; // Same as CPU endian. No need to swap bytes.
|
||||
else if(bom == 0xfffe)
|
||||
else if(bom == 0xfffe)
|
||||
swap = true; // Not same as CPU endian. Need to swap bytes.
|
||||
else {
|
||||
debug("String::copyFromUTF16() - Invalid UTF16 string.");
|
||||
@ -774,7 +766,7 @@ void String::copyFromUTF16(const char *s, size_t length, Type t)
|
||||
s += 2;
|
||||
length -= 2;
|
||||
}
|
||||
else
|
||||
else
|
||||
swap = (t != WCharByteOrder);
|
||||
|
||||
d->data->resize(length / 2);
|
||||
@ -784,7 +776,7 @@ void String::copyFromUTF16(const char *s, size_t length, Type t)
|
||||
}
|
||||
}
|
||||
|
||||
const String::Type String::WCharByteOrder
|
||||
const String::Type String::WCharByteOrder
|
||||
= (Utils::SystemByteOrder == BigEndian) ? String::UTF16BE : String::UTF16LE;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -94,7 +94,7 @@ namespace TagLib {
|
||||
*/
|
||||
UTF16 = 1,
|
||||
/*!
|
||||
* UTF16 <i>big endian</i>. 16 bit characters.
|
||||
* UTF16 <i>big endian</i>. 16 bit characters.
|
||||
*/
|
||||
UTF16BE = 2,
|
||||
/*!
|
||||
@ -130,20 +130,20 @@ namespace TagLib {
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*
|
||||
* \note This should only be used with the 16-bit codecs UTF16, UTF16BE or
|
||||
* UTF16LE, when used with other codecs it will simply print a warning and
|
||||
* exit. UTF16BE or UTF16LE is automatically chosen as default according
|
||||
* to the CPU byte order
|
||||
* \note This should only be used with the 16-bit codecs UTF16, UTF16BE or
|
||||
* UTF16LE, when used with other codecs it will simply print a warning and
|
||||
* exit. UTF16BE or UTF16LE is automatically chosen as default according
|
||||
* to the CPU byte order
|
||||
*/
|
||||
String(const std::wstring &s, Type t = WCharByteOrder);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*
|
||||
* \note This should only be used with the 16-bit codecs UTF16, UTF16BE or
|
||||
* UTF16LE, when used with other codecs it will simply print a warning and
|
||||
* exit. UTF16BE or UTF16LE is automatically chosen as default according
|
||||
* to the CPU byte order
|
||||
* \note This should only be used with the 16-bit codecs UTF16, UTF16BE or
|
||||
* UTF16LE, when used with other codecs it will simply print a warning and
|
||||
* exit. UTF16BE or UTF16LE is automatically chosen as default according
|
||||
* to the CPU byte order
|
||||
*/
|
||||
String(const wchar_t *s, Type t = WCharByteOrder);
|
||||
|
||||
@ -158,10 +158,10 @@ namespace TagLib {
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a c.
|
||||
*
|
||||
* \note This should only be used with the 16-bit codecs UTF16, UTF16BE or
|
||||
* UTF16LE, when used with other codecs it will simply print a warning and
|
||||
* exit. UTF16BE or UTF16LE is automatically chosen as default according
|
||||
* to the CPU byte order
|
||||
* \note This should only be used with the 16-bit codecs UTF16, UTF16BE or
|
||||
* UTF16LE, when used with other codecs it will simply print a warning and
|
||||
* exit. UTF16BE or UTF16LE is automatically chosen as default according
|
||||
* to the CPU byte order
|
||||
*/
|
||||
String(wchar_t c, Type t = WCharByteOrder);
|
||||
|
||||
@ -185,7 +185,7 @@ namespace TagLib {
|
||||
virtual ~String();
|
||||
|
||||
/*!
|
||||
* Returns a deep copy of this String as an std::string. The returned string
|
||||
* Returns a deep copy of this String as an std::string. The returned string
|
||||
* is encoded in UTF8 if \a unicode is true, otherwise Latin1.
|
||||
*
|
||||
* \see toCString()
|
||||
@ -193,7 +193,7 @@ namespace TagLib {
|
||||
std::string to8Bit(bool unicode = false) const;
|
||||
|
||||
/*!
|
||||
* Returns a deep copy of this String as a wstring. The returned string is
|
||||
* Returns a deep copy of this String as a wstring. The returned string is
|
||||
* encoded in UTF-16 (without BOM/CPU byte order).
|
||||
*
|
||||
* \see toCWString()
|
||||
@ -201,43 +201,43 @@ namespace TagLib {
|
||||
const std::wstring &toWString() const;
|
||||
|
||||
/*!
|
||||
* Creates and returns a standard C-style (null-terminated) version of this
|
||||
* String. The returned string is encoded in UTF8 if \a unicode is true,
|
||||
* Creates and returns a standard C-style (null-terminated) version of this
|
||||
* String. The returned string is encoded in UTF8 if \a unicode is true,
|
||||
* otherwise Latin1.
|
||||
*
|
||||
* The returned string is still owned by this String and should not be deleted
|
||||
*
|
||||
* The returned string is still owned by this String and should not be deleted
|
||||
* by the user.
|
||||
*
|
||||
* The returned pointer remains valid until this String instance is destroyed
|
||||
* The returned pointer remains valid until this String instance is destroyed
|
||||
* or toCString() is called again.
|
||||
*
|
||||
* \warning This however has the side effect that the returned string will remain
|
||||
* in memory <b>in addition to</b> other memory that is consumed by this
|
||||
* in memory <b>in addition to</b> other memory that is consumed by this
|
||||
* String instance. So, this method should not be used on large strings or
|
||||
* where memory is critical. Consider using to8Bit() instead to avoid it.
|
||||
*
|
||||
* \see to8Bit()
|
||||
*/
|
||||
const char *toCString(bool unicode = false) const;
|
||||
|
||||
|
||||
/*!
|
||||
* Returns a standard C-style (null-terminated) wide character version of
|
||||
* this String. The returned string is encoded in UTF-16 (without BOM/CPU byte
|
||||
* Returns a standard C-style (null-terminated) wide character version of
|
||||
* this String. The returned string is encoded in UTF-16 (without BOM/CPU byte
|
||||
* order).
|
||||
*
|
||||
* The returned string is still owned by this String and should not be deleted
|
||||
*
|
||||
* The returned string is still owned by this String and should not be deleted
|
||||
* by the user.
|
||||
*
|
||||
* The returned pointer remains valid until this String instance is destroyed
|
||||
* The returned pointer remains valid until this String instance is destroyed
|
||||
* or any other method of this String is called.
|
||||
*
|
||||
* \note This returns a pointer to the String's internal data without any
|
||||
* \note This returns a pointer to the String's internal data without any
|
||||
* conversions.
|
||||
*
|
||||
* \see toWString()
|
||||
*/
|
||||
const wchar_t *toCWString() const;
|
||||
|
||||
|
||||
/*!
|
||||
* Returns an iterator pointing to the beginning of the string.
|
||||
*/
|
||||
@ -332,6 +332,8 @@ namespace TagLib {
|
||||
* Returns a ByteVector containing the string's data. If \a t is Latin1 or
|
||||
* UTF8, this will return a vector of 8 bit characters, otherwise it will use
|
||||
* 16 bit characters.
|
||||
*
|
||||
* \note The returned data is not null terminated.
|
||||
*/
|
||||
ByteVector data(Type t) const;
|
||||
|
||||
@ -477,7 +479,7 @@ namespace TagLib {
|
||||
static const String null;
|
||||
|
||||
/*!
|
||||
* When used as the value for a \a length parameter in String's member
|
||||
* When used as the value for a \a length parameter in String's member
|
||||
* functions, means "until the end of the string".
|
||||
* As a return value, it is usually used to indicate no matches.
|
||||
*/
|
||||
@ -493,31 +495,31 @@ namespace TagLib {
|
||||
|
||||
private:
|
||||
/*!
|
||||
* Converts a \e Latin-1 string into \e UTF-16(without BOM/CPU byte order)
|
||||
* Converts a \e Latin-1 string into \e UTF-16(without BOM/CPU byte order)
|
||||
* and copies it to the internal buffer.
|
||||
*/
|
||||
void copyFromLatin1(const char *s, size_t length);
|
||||
|
||||
/*!
|
||||
* Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order)
|
||||
* Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order)
|
||||
* and copies it to the internal buffer.
|
||||
*/
|
||||
void copyFromUTF8(const char *s, size_t length);
|
||||
|
||||
/*!
|
||||
* Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into
|
||||
* Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into
|
||||
* \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer.
|
||||
*/
|
||||
void copyFromUTF16(const wchar_t *s, size_t length, Type t);
|
||||
|
||||
/*!
|
||||
* Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into
|
||||
* Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into
|
||||
* \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer.
|
||||
*/
|
||||
void copyFromUTF16(const char *s, size_t length, Type t);
|
||||
|
||||
/*!
|
||||
* Indicates which byte order of UTF-16 is used to store strings internally.
|
||||
* Indicates which byte order of UTF-16 is used to store strings internally.
|
||||
*
|
||||
* \note \e String::UTF16BE or \e String::UTF16LE
|
||||
*/
|
||||
|
@ -406,97 +406,90 @@ bool XM::File::save()
|
||||
debug("XM::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
seek(17);
|
||||
writeString(d->tag.title(), 20);
|
||||
seek(1, Current);
|
||||
|
||||
seek(38);
|
||||
writeString(d->tag.trackerName(), 20);
|
||||
seek(2, Current);
|
||||
|
||||
seek(60);
|
||||
uint headerSize = 0;
|
||||
if(!readU32L(headerSize))
|
||||
return false;
|
||||
seek(2+2+2, Current);
|
||||
|
||||
seek(70);
|
||||
ushort patternCount = 0;
|
||||
ushort instrumentCount = 0;
|
||||
if(!readU16L(patternCount) || !readU16L(instrumentCount))
|
||||
return false;
|
||||
|
||||
seek(60 + headerSize);
|
||||
long pos = 60 + headerSize; // should be offset_t in taglib2.
|
||||
|
||||
// need to read patterns again in order to seek to the instruments:
|
||||
for(ushort i = 0; i < patternCount; ++ i) {
|
||||
seek(pos);
|
||||
uint patternHeaderLength = 0;
|
||||
if(!readU32L(patternHeaderLength) || patternHeaderLength < 4)
|
||||
return false;
|
||||
|
||||
seek(pos + 7);
|
||||
ushort dataSize = 0;
|
||||
StructReader pattern;
|
||||
pattern.skip(3).u16L(dataSize);
|
||||
|
||||
uint count = pattern.read(*this, patternHeaderLength - 4U);
|
||||
if(count != std::min(patternHeaderLength - 4U, pattern.size()))
|
||||
if (!readU16L(dataSize))
|
||||
return false;
|
||||
|
||||
seek(patternHeaderLength - (4 + count) + dataSize, Current);
|
||||
pos += patternHeaderLength + dataSize;
|
||||
}
|
||||
|
||||
StringList lines = d->tag.comment().split("\n");
|
||||
const StringList lines = d->tag.comment().split("\n");
|
||||
uint sampleNameIndex = instrumentCount;
|
||||
for(ushort i = 0; i < instrumentCount; ++ i) {
|
||||
seek(pos);
|
||||
uint instrumentHeaderSize = 0;
|
||||
if(!readU32L(instrumentHeaderSize) || instrumentHeaderSize < 4)
|
||||
return false;
|
||||
|
||||
uint len = std::min(22U, instrumentHeaderSize - 4U);
|
||||
seek(pos + 4);
|
||||
const uint len = std::min(22U, instrumentHeaderSize - 4U);
|
||||
if(i >= lines.size())
|
||||
writeString(String::null, len);
|
||||
else
|
||||
writeString(lines[i], len);
|
||||
|
||||
long offset = 0;
|
||||
ushort sampleCount = 0;
|
||||
if(instrumentHeaderSize >= 29U) {
|
||||
ushort sampleCount = 0;
|
||||
seek(1, Current);
|
||||
seek(pos + 27);
|
||||
if(!readU16L(sampleCount))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sampleCount > 0) {
|
||||
uint sampleHeaderSize = 0;
|
||||
if(instrumentHeaderSize < 33U || !readU32L(sampleHeaderSize))
|
||||
uint sampleHeaderSize = 0;
|
||||
if(sampleCount > 0) {
|
||||
seek(pos + 29);
|
||||
if(instrumentHeaderSize < 33U || !readU32L(sampleHeaderSize))
|
||||
return false;
|
||||
}
|
||||
|
||||
pos += instrumentHeaderSize;
|
||||
|
||||
for(ushort j = 0; j < sampleCount; ++ j) {
|
||||
if(sampleHeaderSize > 4U) {
|
||||
seek(pos);
|
||||
uint sampleLength = 0;
|
||||
if(!readU32L(sampleLength))
|
||||
return false;
|
||||
// skip unhandeled header proportion:
|
||||
seek(instrumentHeaderSize - 33, Current);
|
||||
|
||||
for(ushort j = 0; j < sampleCount; ++ j) {
|
||||
if(sampleHeaderSize > 4U) {
|
||||
uint sampleLength = 0;
|
||||
if(!readU32L(sampleLength))
|
||||
return false;
|
||||
offset += sampleLength;
|
||||
|
||||
seek(std::min(sampleHeaderSize, 14U), Current);
|
||||
if(sampleHeaderSize > 18U) {
|
||||
uint len = std::min(sampleHeaderSize - 18U, 22U);
|
||||
if(sampleNameIndex >= lines.size())
|
||||
writeString(String::null, len);
|
||||
else
|
||||
writeString(lines[sampleNameIndex ++], len);
|
||||
seek(sampleHeaderSize - (18U + len), Current);
|
||||
}
|
||||
}
|
||||
else {
|
||||
seek(sampleHeaderSize, Current);
|
||||
}
|
||||
if(sampleHeaderSize > 18U) {
|
||||
seek(pos + 18);
|
||||
const uint len = std::min(sampleHeaderSize - 18U, 22U);
|
||||
if(sampleNameIndex >= lines.size())
|
||||
writeString(String::null, len);
|
||||
else
|
||||
writeString(lines[sampleNameIndex ++], len);
|
||||
}
|
||||
}
|
||||
else {
|
||||
offset = instrumentHeaderSize - 29;
|
||||
}
|
||||
pos += sampleHeaderSize;
|
||||
}
|
||||
else {
|
||||
offset = instrumentHeaderSize - (4 + len);
|
||||
}
|
||||
seek(offset, Current);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -45,6 +45,7 @@ class TestString : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testSubstr);
|
||||
CPPUNIT_TEST(testNewline);
|
||||
CPPUNIT_TEST(testUpper);
|
||||
CPPUNIT_TEST(testEncode);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@ -200,10 +201,10 @@ public:
|
||||
String a("abc");
|
||||
String b = a;
|
||||
String c = a;
|
||||
|
||||
|
||||
b += 'd';
|
||||
c += L'd';
|
||||
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(String("abc"), a);
|
||||
CPPUNIT_ASSERT_EQUAL(String("abcd"), b);
|
||||
CPPUNIT_ASSERT_EQUAL(String("abcd"), c);
|
||||
@ -277,7 +278,7 @@ public:
|
||||
CPPUNIT_ASSERT_EQUAL(L'\x0d', String(crlf)[3]);
|
||||
CPPUNIT_ASSERT_EQUAL(L'\x0a', String(crlf)[4]);
|
||||
}
|
||||
|
||||
|
||||
void testUpper()
|
||||
{
|
||||
String s1 = "tagLIB 012 strING";
|
||||
@ -286,6 +287,43 @@ public:
|
||||
CPPUNIT_ASSERT_EQUAL(String("TAGLIB 012 STRING"), s2);
|
||||
}
|
||||
|
||||
void testEncode()
|
||||
{
|
||||
String jpn(L"\u65E5\u672C\u8A9E");
|
||||
ByteVector jpn1 = jpn.data(String::Latin1);
|
||||
ByteVector jpn2 = jpn.data(String::UTF8);
|
||||
ByteVector jpn3 = jpn.data(String::UTF16);
|
||||
ByteVector jpn4 = jpn.data(String::UTF16LE);
|
||||
ByteVector jpn5 = jpn.data(String::UTF16BE);
|
||||
std::string jpn6 = jpn.to8Bit(false);
|
||||
std::string jpn7 = jpn.to8Bit(true);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("\xE5\x2C\x9E"), jpn1);
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"), jpn2);
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("\xFF\xFE\xE5\x65\x2C\x67\x9E\x8A"), jpn3);
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("\xE5\x65\x2C\x67\x9E\x8A"), jpn4);
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("\x65\xE5\x67\x2C\x8A\x9E"), jpn5);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("\xE5\x2C\x9E"), jpn6);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"), jpn7);
|
||||
|
||||
String empty;
|
||||
ByteVector empty1 = empty.data(String::Latin1);
|
||||
ByteVector empty2 = empty.data(String::UTF8);
|
||||
ByteVector empty3 = empty.data(String::UTF16);
|
||||
ByteVector empty4 = empty.data(String::UTF16LE);
|
||||
ByteVector empty5 = empty.data(String::UTF16BE);
|
||||
std::string empty6 = empty.to8Bit(false);
|
||||
std::string empty7 = empty.to8Bit(true);
|
||||
|
||||
CPPUNIT_ASSERT(empty1.isEmpty());
|
||||
CPPUNIT_ASSERT(empty2.isEmpty());
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("\xFF\xFE"), empty3);
|
||||
CPPUNIT_ASSERT(empty4.isEmpty());
|
||||
CPPUNIT_ASSERT(empty5.isEmpty());
|
||||
CPPUNIT_ASSERT(empty6.empty());
|
||||
CPPUNIT_ASSERT(empty7.empty());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestString);
|
||||
|
Loading…
x
Reference in New Issue
Block a user