Clementine-audio-player-Mac.../3rdparty/taglib/toolkit/tstring.cpp

748 lines
16 KiB
C++
Raw Normal View History

2012-10-28 02:12:18 +02:00
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
2016-07-19 16:58:52 +02:00
#include <cerrno>
#include <climits>
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
#include <utf8-cpp/checked.h>
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
#include <tdebug.h>
#include <tstringlist.h>
#include <trefcounter.h>
#include <tutils.h>
#include "tstring.h"
2015-11-24 19:36:24 +01:00
namespace
{
2015-11-24 19:36:24 +01:00
using namespace TagLib;
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
// Returns the native format of std::wstring.
String::Type wcharByteOrder()
{
if(Utils::systemByteOrder() == Utils::LittleEndian)
return String::UTF16LE;
else
return String::UTF16BE;
}
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
// Converts a Latin-1 string into UTF-16(without BOM/CPU byte order)
// and copies it to the internal buffer.
void copyFromLatin1(std::wstring &data, const char *s, size_t length)
{
data.resize(length);
for(size_t i = 0; i < length; ++i)
data[i] = static_cast<unsigned char>(s[i]);
}
// Converts a UTF-8 string into UTF-16(without BOM/CPU byte order)
// and copies it to the internal buffer.
void copyFromUTF8(std::wstring &data, const char *s, size_t length)
{
2016-07-19 16:58:52 +02:00
data.resize(length);
2018-06-06 22:47:08 +02:00
try {
const std::wstring::iterator dstEnd = utf8::utf8to16(s, s + length, data.begin());
data.resize(dstEnd - data.begin());
}
catch(const utf8::exception &e) {
const String message(e.what());
debug("String::copyFromUTF8() - UTF8-CPP error: " + message);
data.clear();
2016-07-19 16:58:52 +02:00
}
}
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
// Helper functions to read a UTF-16 character from an array.
template <typename T>
unsigned short nextUTF16(const T **p);
2016-07-19 16:58:52 +02:00
2018-06-06 22:47:08 +02:00
template <>
unsigned short nextUTF16<wchar_t>(const wchar_t **p)
{
return static_cast<unsigned short>(*(*p)++);
}
2016-07-19 16:58:52 +02:00
2018-06-06 22:47:08 +02:00
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;
}
2015-11-24 19:36:24 +01:00
2016-07-19 16:58:52 +02:00
// 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.
2018-06-06 22:47:08 +02:00
template <typename T>
void copyFromUTF16(std::wstring &data, const T *s, size_t length, String::Type t)
{
2016-07-19 16:58:52 +02:00
bool swap;
if(t == String::UTF16) {
2018-06-06 22:47:08 +02:00
if(length < 1) {
debug("String::copyFromUTF16() - Invalid UTF16 string. Too short to have a BOM.");
2016-07-19 16:58:52 +02:00
return;
}
2018-06-06 22:47:08 +02:00
const unsigned short bom = nextUTF16(&s);
2016-07-19 16:58:52 +02:00
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 {
2018-06-06 22:47:08 +02:00
debug("String::copyFromUTF16() - Invalid UTF16 string. BOM is broken.");
2016-07-19 16:58:52 +02:00
return;
}
2018-06-06 22:47:08 +02:00
length--;
2016-07-19 16:58:52 +02:00
}
else {
swap = (t != wcharByteOrder());
}
2018-06-06 22:47:08 +02:00
data.resize(length);
for(size_t i = 0; i < length; ++i) {
const unsigned short c = nextUTF16(&s);
2016-07-19 16:58:52 +02:00
if(swap)
2018-06-06 22:47:08 +02:00
data[i] = Utils::byteSwap(c);
else
data[i] = c;
2016-07-19 16:58:52 +02:00
}
2012-10-28 02:12:18 +02:00
}
2016-07-19 16:58:52 +02:00
}
namespace TagLib {
class String::StringPrivate : public RefCounter
{
public:
StringPrivate() :
RefCounter() {}
/*!
2015-11-24 19:36:24 +01:00
* Stores string in UTF-16. The byte order depends on the CPU endian.
*/
TagLib::wstring data;
2012-10-28 02:12:18 +02:00
/*!
* This is only used to hold the the most recent value of toCString().
2012-10-28 02:12:18 +02:00
*/
std::string cstring;
2012-10-28 02:12:18 +02:00
};
String String::null;
2016-07-19 16:58:52 +02:00
////////////////////////////////////////////////////////////////////////////////
// public members
2012-10-28 02:12:18 +02:00
////////////////////////////////////////////////////////////////////////////////
2016-07-19 16:58:52 +02:00
String::String() :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
}
2016-07-19 16:58:52 +02:00
String::String(const String &s) :
d(s.d)
2012-10-28 02:12:18 +02:00
{
d->ref();
}
2016-07-19 16:58:52 +02:00
String::String(const std::string &s, Type t) :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
if(t == Latin1)
2016-07-19 16:58:52 +02:00
copyFromLatin1(d->data, s.c_str(), s.length());
else if(t == String::UTF8)
2016-07-19 16:58:52 +02:00
copyFromUTF8(d->data, s.c_str(), s.length());
else {
2015-11-24 19:36:24 +01:00
debug("String::String() -- std::string should not contain UTF16.");
2012-10-28 02:12:18 +02:00
}
}
2016-07-19 16:58:52 +02:00
String::String(const wstring &s, Type t) :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
2015-11-24 19:36:24 +01:00
if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
// This looks ugly but needed for the compatibility with TagLib1.8.
// Should be removed in TabLib2.0.
if (t == UTF16BE)
2016-07-19 16:58:52 +02:00
t = wcharByteOrder();
2015-11-24 19:36:24 +01:00
else if (t == UTF16LE)
2016-07-19 16:58:52 +02:00
t = (wcharByteOrder() == UTF16LE ? UTF16BE : UTF16LE);
2015-11-24 19:36:24 +01:00
2016-07-19 16:58:52 +02:00
copyFromUTF16(d->data, s.c_str(), s.length(), t);
2015-11-24 19:36:24 +01:00
}
else {
2015-11-24 19:36:24 +01:00
debug("String::String() -- TagLib::wstring should not contain Latin1 or UTF-8.");
}
2012-10-28 02:12:18 +02:00
}
2016-07-19 16:58:52 +02:00
String::String(const wchar_t *s, Type t) :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
2015-11-24 19:36:24 +01:00
if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
// This looks ugly but needed for the compatibility with TagLib1.8.
// Should be removed in TabLib2.0.
if (t == UTF16BE)
2016-07-19 16:58:52 +02:00
t = wcharByteOrder();
2015-11-24 19:36:24 +01:00
else if (t == UTF16LE)
2016-07-19 16:58:52 +02:00
t = (wcharByteOrder() == UTF16LE ? UTF16BE : UTF16LE);
2015-11-24 19:36:24 +01:00
2016-07-19 16:58:52 +02:00
copyFromUTF16(d->data, s, ::wcslen(s), t);
2015-11-24 19:36:24 +01:00
}
else {
2015-11-24 19:36:24 +01:00
debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8.");
}
2012-10-28 02:12:18 +02:00
}
2016-07-19 16:58:52 +02:00
String::String(const char *s, Type t) :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
if(t == Latin1)
2016-07-19 16:58:52 +02:00
copyFromLatin1(d->data, s, ::strlen(s));
else if(t == String::UTF8)
2016-07-19 16:58:52 +02:00
copyFromUTF8(d->data, s, ::strlen(s));
else {
2015-11-24 19:36:24 +01:00
debug("String::String() -- const char * should not contain UTF16.");
2012-10-28 02:12:18 +02:00
}
}
2016-07-19 16:58:52 +02:00
String::String(wchar_t c, Type t) :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
if(t == UTF16 || t == UTF16BE || t == UTF16LE)
2016-07-19 16:58:52 +02:00
copyFromUTF16(d->data, &c, 1, t);
else {
2015-11-24 19:36:24 +01:00
debug("String::String() -- wchar_t should not contain Latin1 or UTF-8.");
}
2012-10-28 02:12:18 +02:00
}
2016-07-19 16:58:52 +02:00
String::String(char c, Type t) :
2018-06-06 22:47:08 +02:00
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
2018-06-06 22:47:08 +02:00
if(t == Latin1)
copyFromLatin1(d->data, &c, 1);
else if(t == String::UTF8)
copyFromUTF8(d->data, &c, 1);
else {
2015-11-24 19:36:24 +01:00
debug("String::String() -- char should not contain UTF16.");
2012-10-28 02:12:18 +02:00
}
}
2016-07-19 16:58:52 +02:00
String::String(const ByteVector &v, Type t) :
d(new StringPrivate())
2012-10-28 02:12:18 +02:00
{
if(v.isEmpty())
return;
2015-11-24 19:36:24 +01:00
if(t == Latin1)
2016-07-19 16:58:52 +02:00
copyFromLatin1(d->data, v.data(), v.size());
2015-11-24 19:36:24 +01:00
else if(t == UTF8)
2016-07-19 16:58:52 +02:00
copyFromUTF8(d->data, v.data(), v.size());
2015-11-24 19:36:24 +01:00
else
2018-06-06 22:47:08 +02:00
copyFromUTF16(d->data, v.data(), v.size() / 2, t);
2013-12-17 19:38:05 +01:00
// If we hit a null in the ByteVector, shrink the string again.
d->data.resize(::wcslen(d->data.c_str()));
2012-10-28 02:12:18 +02:00
}
////////////////////////////////////////////////////////////////////////////////
String::~String()
{
if(d->deref())
delete d;
}
std::string String::to8Bit(bool unicode) const
{
2015-11-24 19:36:24 +01:00
const ByteVector v = data(unicode ? UTF8 : Latin1);
return std::string(v.data(), v.size());
2012-10-28 02:12:18 +02:00
}
TagLib::wstring String::toWString() const
{
return d->data;
}
const char *String::toCString(bool unicode) const
{
d->cstring = to8Bit(unicode);
return d->cstring.c_str();
}
2012-10-28 02:12:18 +02:00
const wchar_t *String::toCWString() const
{
return d->data.c_str();
2012-10-28 02:12:18 +02:00
}
String::Iterator String::begin()
{
2015-11-24 19:36:24 +01:00
detach();
2012-10-28 02:12:18 +02:00
return d->data.begin();
}
String::ConstIterator String::begin() const
{
return d->data.begin();
}
String::Iterator String::end()
{
2015-11-24 19:36:24 +01:00
detach();
2012-10-28 02:12:18 +02:00
return d->data.end();
}
String::ConstIterator String::end() const
{
return d->data.end();
}
int String::find(const String &s, int offset) const
{
2018-06-06 22:47:08 +02:00
return static_cast<int>(d->data.find(s.d->data, offset));
2012-10-28 02:12:18 +02:00
}
int String::rfind(const String &s, int offset) const
{
2018-06-06 22:47:08 +02:00
return static_cast<int>(d->data.rfind(s.d->data, offset));
2012-10-28 02:12:18 +02:00
}
StringList String::split(const String &separator) const
{
StringList list;
2015-11-24 19:36:24 +01:00
for(int index = 0;;) {
2012-10-28 02:12:18 +02:00
int sep = find(separator, index);
2015-11-24 19:36:24 +01:00
if(sep < 0) {
2012-10-28 02:12:18 +02:00
list.append(substr(index, size() - index));
break;
}
2015-11-24 19:36:24 +01:00
else {
2012-10-28 02:12:18 +02:00
list.append(substr(index, sep - index));
index = sep + separator.size();
}
}
return list;
}
bool String::startsWith(const String &s) const
{
if(s.length() > length())
return false;
return substr(0, s.length()) == s;
}
2016-07-19 16:58:52 +02:00
String String::substr(unsigned int position, unsigned int n) const
2012-10-28 02:12:18 +02:00
{
2018-06-06 22:47:08 +02:00
if(position == 0 && n >= size())
return *this;
else
return String(d->data.substr(position, n));
2012-10-28 02:12:18 +02:00
}
String &String::append(const String &s)
{
detach();
d->data += s.d->data;
return *this;
}
2016-07-19 16:58:52 +02:00
String & String::clear()
{
*this = String();
return *this;
}
2012-10-28 02:12:18 +02:00
String String::upper() const
{
String s;
2018-06-06 22:47:08 +02:00
s.d->data.reserve(size());
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it) {
2012-10-28 02:12:18 +02:00
if(*it >= 'a' && *it <= 'z')
2018-06-06 22:47:08 +02:00
s.d->data.push_back(*it + 'A' - 'a');
2012-10-28 02:12:18 +02:00
else
s.d->data.push_back(*it);
}
return s;
}
2016-07-19 16:58:52 +02:00
unsigned int String::size() const
2012-10-28 02:12:18 +02:00
{
2018-06-06 22:47:08 +02:00
return static_cast<unsigned int>(d->data.size());
2012-10-28 02:12:18 +02:00
}
2016-07-19 16:58:52 +02:00
unsigned int String::length() const
2012-10-28 02:12:18 +02:00
{
return size();
}
bool String::isEmpty() const
{
2016-07-19 16:58:52 +02:00
return d->data.empty();
2012-10-28 02:12:18 +02:00
}
bool String::isNull() const
{
return d == null.d;
}
ByteVector String::data(Type t) const
{
2015-11-24 19:36:24 +01:00
switch(t)
{
case Latin1:
{
ByteVector v(size(), 0);
char *p = v.data();
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it)
*p++ = static_cast<char>(*it);
2012-10-28 02:12:18 +02:00
return v;
}
2012-10-28 02:12:18 +02:00
case UTF8:
{
2018-06-06 22:47:08 +02:00
ByteVector v(size() * 4, 0);
2018-06-06 22:47:08 +02:00
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) {
const String message(e.what());
debug("String::data() - UTF8-CPP error: " + message);
v.clear();
}
return v;
}
2012-10-28 02:12:18 +02:00
case UTF16:
{
ByteVector v(2 + size() * 2, 0);
char *p = v.data();
2012-10-28 02:12:18 +02:00
2015-11-24 19:36:24 +01:00
// We use little-endian encoding here and need a BOM.
2012-10-28 02:12:18 +02:00
*p++ = '\xff';
*p++ = '\xfe';
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it) {
*p++ = static_cast<char>(*it & 0xff);
*p++ = static_cast<char>(*it >> 8);
}
2012-10-28 02:12:18 +02:00
return v;
2012-10-28 02:12:18 +02:00
}
case UTF16BE:
{
ByteVector v(size() * 2, 0);
char *p = v.data();
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it) {
*p++ = static_cast<char>(*it >> 8);
*p++ = static_cast<char>(*it & 0xff);
}
2012-10-28 02:12:18 +02:00
return v;
2012-10-28 02:12:18 +02:00
}
case UTF16LE:
{
ByteVector v(size() * 2, 0);
char *p = v.data();
2012-10-28 02:12:18 +02:00
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it) {
*p++ = static_cast<char>(*it & 0xff);
*p++ = static_cast<char>(*it >> 8);
}
2012-10-28 02:12:18 +02:00
return v;
}
default:
{
debug("String::data() - Invalid Type value.");
2016-07-19 16:58:52 +02:00
return ByteVector();
2012-10-28 02:12:18 +02:00
}
}
}
int String::toInt() const
{
return toInt(0);
}
int String::toInt(bool *ok) const
{
2016-07-19 16:58:52 +02:00
const wchar_t *begin = d->data.c_str();
wchar_t *end;
errno = 0;
const long value = ::wcstol(begin, &end, 10);
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
// Has wcstol() consumed the entire string and not overflowed?
if(ok) {
*ok = (errno == 0 && end > begin && *end == L'\0');
*ok = (*ok && value > INT_MIN && value < INT_MAX);
}
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
return static_cast<int>(value);
2012-10-28 02:12:18 +02:00
}
String String::stripWhiteSpace() const
{
2016-07-19 16:58:52 +02:00
static const wchar_t *WhiteSpaceChars = L"\t\n\f\r ";
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
const size_t pos1 = d->data.find_first_not_of(WhiteSpaceChars);
if(pos1 == std::wstring::npos)
return String();
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
const size_t pos2 = d->data.find_last_not_of(WhiteSpaceChars);
2018-06-06 22:47:08 +02:00
return substr(static_cast<unsigned int>(pos1), static_cast<unsigned int>(pos2 - pos1 + 1));
2012-10-28 02:12:18 +02:00
}
bool String::isLatin1() const
{
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it) {
2012-10-28 02:12:18 +02:00
if(*it >= 256)
return false;
}
return true;
}
bool String::isAscii() const
{
2018-06-06 22:47:08 +02:00
for(ConstIterator it = begin(); it != end(); ++it) {
2012-10-28 02:12:18 +02:00
if(*it >= 128)
return false;
}
return true;
}
String String::number(int n) // static
{
2015-11-24 19:36:24 +01:00
return Utils::formatString("%d", n);
2012-10-28 02:12:18 +02:00
}
2016-07-19 16:58:52 +02:00
wchar_t &String::operator[](int i)
2012-10-28 02:12:18 +02:00
{
detach();
return d->data[i];
}
2016-07-19 16:58:52 +02:00
const wchar_t &String::operator[](int i) const
2012-10-28 02:12:18 +02:00
{
return d->data[i];
}
bool String::operator==(const String &s) const
{
2015-11-24 19:36:24 +01:00
return (d == s.d || d->data == s.d->data);
2012-10-28 02:12:18 +02:00
}
bool String::operator!=(const String &s) const
{
2015-11-24 19:36:24 +01:00
return !(*this == s);
}
bool String::operator==(const char *s) const
{
const wchar_t *p = toCWString();
while(*p != L'\0' || *s != '\0') {
2016-07-19 16:58:52 +02:00
if(*p++ != static_cast<unsigned char>(*s++))
2015-11-24 19:36:24 +01:00
return false;
}
return true;
}
bool String::operator!=(const char *s) const
{
return !(*this == s);
}
bool String::operator==(const wchar_t *s) const
{
return (d->data == s);
}
bool String::operator!=(const wchar_t *s) const
{
return !(*this == s);
2012-10-28 02:12:18 +02:00
}
String &String::operator+=(const String &s)
{
detach();
d->data += s.d->data;
return *this;
}
String &String::operator+=(const wchar_t *s)
{
detach();
d->data += s;
return *this;
}
String &String::operator+=(const char *s)
{
detach();
for(int i = 0; s[i] != 0; i++)
2016-07-19 16:58:52 +02:00
d->data += static_cast<unsigned char>(s[i]);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator+=(wchar_t c)
{
detach();
d->data += c;
return *this;
}
String &String::operator+=(char c)
{
detach();
2016-07-19 16:58:52 +02:00
d->data += static_cast<unsigned char>(c);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(const String &s)
{
2016-07-19 16:58:52 +02:00
String(s).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(const std::string &s)
{
2016-07-19 16:58:52 +02:00
String(s).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(const wstring &s)
{
2016-07-19 16:58:52 +02:00
String(s).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(const wchar_t *s)
{
2016-07-19 16:58:52 +02:00
String(s).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(char c)
{
2016-07-19 16:58:52 +02:00
String(c).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(wchar_t c)
{
2016-07-19 16:58:52 +02:00
String(c, wcharByteOrder()).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(const char *s)
{
2016-07-19 16:58:52 +02:00
String(s).swap(*this);
2012-10-28 02:12:18 +02:00
return *this;
}
String &String::operator=(const ByteVector &v)
{
2016-07-19 16:58:52 +02:00
String(v).swap(*this);
return *this;
}
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
void String::swap(String &s)
{
using std::swap;
2012-10-28 02:12:18 +02:00
2016-07-19 16:58:52 +02:00
swap(d, s.d);
2012-10-28 02:12:18 +02:00
}
bool String::operator<(const String &s) const
{
2016-07-19 16:58:52 +02:00
return (d->data < s.d->data);
2012-10-28 02:12:18 +02:00
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void String::detach()
{
2016-07-19 16:58:52 +02:00
if(d->count() > 1)
String(d->data.c_str()).swap(*this);
2012-10-28 02:12:18 +02:00
}
2018-06-06 22:47:08 +02:00
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
const String::Type String::WCharByteOrder = wcharByteOrder();
}
2012-10-28 02:12:18 +02:00
////////////////////////////////////////////////////////////////////////////////
2016-07-19 16:58:52 +02:00
// related non-member functions
2012-10-28 02:12:18 +02:00
////////////////////////////////////////////////////////////////////////////////
const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2)
{
TagLib::String s(s1);
2012-10-28 02:12:18 +02:00
s.append(s2);
return s;
}
const TagLib::String operator+(const char *s1, const TagLib::String &s2)
{
TagLib::String s(s1);
2012-10-28 02:12:18 +02:00
s.append(s2);
return s;
}
const TagLib::String operator+(const TagLib::String &s1, const char *s2)
{
TagLib::String s(s1);
2012-10-28 02:12:18 +02:00
s.append(s2);
return s;
}
std::ostream &operator<<(std::ostream &s, const TagLib::String &str)
2012-10-28 02:12:18 +02:00
{
s << str.to8Bit();
return s;
}