summaryrefslogtreecommitdiffstats
path: root/patches/taglib
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2021-03-12 03:55:34 +0100
committerSuren A. Chilingaryan <csa@suren.me>2021-03-12 03:55:34 +0100
commit60bd665e74cfeeaf70882173a0dd56c883e2014a (patch)
tree8a0066bb9f0259becac5605641e8e1eed1ae0e89 /patches/taglib
downloadrusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.tar.gz
rusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.tar.bz2
rusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.tar.xz
rusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.zip
Added to git tree
Diffstat (limited to 'patches/taglib')
-rw-r--r--patches/taglib/README36
-rw-r--r--patches/taglib/taglib-1.10-ds-rusxmms.patch1339
-rw-r--r--patches/taglib/taglib-1.11-ds-rusxmms.patch684
-rw-r--r--patches/taglib/taglib-1.4-ds-rusxmms.patch504
-rw-r--r--patches/taglib/taglib-1.5-ds-rusxmms.patch584
-rw-r--r--patches/taglib/taglib-1.6-ds-rusxmms.patch587
-rw-r--r--patches/taglib/taglib-1.7-ds-rusxmms-r2.patch506
-rw-r--r--patches/taglib/taglib-1.7-ds-rusxmms.patch515
-rw-r--r--patches/taglib/taglib-1.8-ds-rusxmms-r2.patch507
-rw-r--r--patches/taglib/taglib-1.8-ds-rusxmms-r9.patch609
-rw-r--r--patches/taglib/taglib-1.8-ds-rusxmms.patch519
-rw-r--r--patches/taglib/taglib-1.9.1-ds-rusxmms-enforce.patch20
-rw-r--r--patches/taglib/taglib-1.9.1-ds-rusxmms.patch676
13 files changed, 7086 insertions, 0 deletions
diff --git a/patches/taglib/README b/patches/taglib/README
new file mode 100644
index 0000000..0d3e78e
--- /dev/null
+++ b/patches/taglib/README
@@ -0,0 +1,36 @@
+taglib-*-ds-rusxmms-enforce.patch will prevent applications from
+overloading taglib ID3 v.1 parser/renderer. For instance, kid3
+has it's onw recoder and bypasses RusXMMS unless this patch is
+applied.
+
+If you want to set unicode ID3v.2 titles, please, set in the
+LibRCC configuration (xmms.xml) "id3v2" class to point appropriate
+unicode encoding.
+
+1. Some Info Encoding Handling
+1.1 Reading encodings
+ - Unicode ID3 v.2 tags are read as defined by ID3V2 tag, no RusXMMS
+ is envolved.
+ - Latin1 ID3 v.2 and ID3 v.1 tags are read using RusXMMS library.
+ The 'id3' and 'id3v2' classes are used corespondingly.
+1.2 Writing ID3 v.1 encodings
+ - ID3 v.1 tag is written using RusXMMS library. The 'id3' class
+ selects output encoding.
+1.3 Writting ID3 v.2 encodings
+ - ID3 v.2 tag output encodings is selected with help of 'id3v2' class of
+ RusXMMS.
+ - If unicode encoding is set (UTF-8, UTF-16, UTF-16BE, UTF-16LE)
+ the tag is written using selected encoding (independent of original one).
+ - Otherwise, original unicode encodings are kept.
+ - If original encoding is also non-unicode, than the tag is stored
+ in 'id3v2' class encoding. However, it is really a bad idea! Set an
+ unicode encoding.
+2. Recomended class settings
+ - id3 = CP1251
+ - id3v2 = UTF-16
+3. Notes
+ - TagLib supports UTF-16LE encodings within ID3 v.2 tags (described by
+ number 4). The UTF-16LE is not part of standard and probably added for
+ compatibility with some nasty Windows applications. RusXMMS will not
+ allow to write tags in UTF-16LE.
+ \ No newline at end of file
diff --git a/patches/taglib/taglib-1.10-ds-rusxmms.patch b/patches/taglib/taglib-1.10-ds-rusxmms.patch
new file mode 100644
index 0000000..584c237
--- /dev/null
+++ b/patches/taglib/taglib-1.10-ds-rusxmms.patch
@@ -0,0 +1,1339 @@
+diff -dPNur taglib-1.10/config.h.cmake taglib-1.10-ds/config.h.cmake
+--- taglib-1.10/config.h.cmake 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/config.h.cmake 2015-11-26 23:03:07.058061207 +0100
+@@ -25,4 +25,7 @@
+ /* Indicates whether debug messages are shown even in release mode */
+ #cmakedefine TRACE_IN_RELEASE 1
+
++/* Defined if you have LibRCC from RusXMMS project */
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine TESTS_DIR "@TESTS_DIR@"
+diff -dPNur taglib-1.10/ConfigureChecks.cmake taglib-1.10-ds/ConfigureChecks.cmake
+--- taglib-1.10/ConfigureChecks.cmake 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/ConfigureChecks.cmake 2015-11-26 23:03:07.058061207 +0100
+@@ -201,6 +201,8 @@
+ endif()
+ endif()
+
++SET(HAVE_LIBRCC 1)
++
+ if(BUILD_TESTS)
+ find_package(CppUnit)
+ if(NOT CppUnit_FOUND)
+diff -dPNur taglib-1.10/examples/tagreader_c.c taglib-1.10-ds/examples/tagreader_c.c
+--- taglib-1.10/examples/tagreader_c.c 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/examples/tagreader_c.c 2015-11-26 23:03:07.059061228 +0100
+@@ -38,7 +38,7 @@
+ TagLib_Tag *tag;
+ const TagLib_AudioProperties *properties;
+
+- taglib_set_strings_unicode(FALSE);
++ //taglib_set_strings_unicode(FALSE);
+
+ for(i = 1; i < argc; i++) {
+ printf("******************** \"%s\" ********************\n", argv[i]);
+diff -dPNur taglib-1.10/examples/tagwriter.cpp taglib-1.10-ds/examples/tagwriter.cpp
+--- taglib-1.10/examples/tagwriter.cpp 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/examples/tagwriter.cpp 2015-11-26 23:03:07.059061228 +0100
+@@ -115,7 +115,7 @@
+ if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
+
+ char field = argv[i][1];
+- TagLib::String value = argv[i + 1];
++ TagLib::String value(argv[i + 1], TagLib::String::Locale);
+
+ TagLib::List<TagLib::FileRef>::ConstIterator it;
+ for(it = fileList.begin(); it != fileList.end(); ++it) {
+diff -dPNur taglib-1.10/taglib/CMakeLists.txt taglib-1.10-ds/taglib/CMakeLists.txt
+--- taglib-1.10/taglib/CMakeLists.txt 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/CMakeLists.txt 2015-11-26 23:03:07.059061228 +0100
+@@ -38,6 +38,7 @@
+ audioproperties.h
+ taglib_export.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../taglib_config.h
++ toolkit/rccpatch.h
+ toolkit/taglib.h
+ toolkit/tstring.h
+ toolkit/tlist.h
+@@ -291,6 +292,7 @@
+ )
+
+ set(toolkit_SRCS
++ toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -337,7 +339,7 @@
+ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
+
+ if(ZLIB_FOUND)
+- target_link_libraries(tag ${ZLIB_LIBRARIES})
++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
+ endif()
+
+ set_target_properties(tag PROPERTIES
+diff -dPNur taglib-1.10/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.10-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.10/taglib/mpeg/id3v1/id3v1tag.cpp 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2015-11-26 23:03:07.059061228 +0100
+@@ -64,17 +64,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -257,7 +258,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.10/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.10-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.10/taglib/mpeg/id3v2/frames/commentsframe.cpp 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2015-11-26 23:03:07.059061228 +0100
+@@ -150,10 +150,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -173,11 +173,13 @@
+ ByteVector v;
+
+ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
+
+ encoding = checkTextEncoding(d->description, encoding);
+ encoding = checkTextEncoding(d->text, encoding);
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.10/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.10-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.10/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2015-11-26 23:03:07.059061228 +0100
+@@ -187,12 +187,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -223,11 +223,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkTextEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.10/taglib/mpeg/id3v2/id3v2frame.cpp taglib-1.10-ds/taglib/mpeg/id3v2/id3v2frame.cpp
+--- taglib-1.10/taglib/mpeg/id3v2/id3v2frame.cpp 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/mpeg/id3v2/id3v2frame.cpp 2015-11-26 23:03:07.060061249 +0100
+@@ -339,7 +339,7 @@
+ if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4)
+ return String::UTF16;
+
+- if(encoding != String::Latin1)
++ if((encoding != String::Latin1)&&(encoding != String::Latin1ID3V2))
+ return encoding;
+
+ for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
+diff -dPNur taglib-1.10/taglib/toolkit/rccpatch.cpp taglib-1.10-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.10/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.10-ds/taglib/toolkit/rccpatch.cpp 2015-11-26 23:03:07.060061249 +0100
+@@ -0,0 +1,237 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++//#define RCC_DEBUG
++
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# ifdef RCC_DEBUG
++# include <stdio.h>
++# endif /* RCC_DEBUG */
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccTaglibPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccTaglibPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccTaglibPatchInit();
++ if (rcc_initialized) atexit(rccTaglibPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Output: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" OutputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Input: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" InputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++ if (res) v.setData(res, rlen + 1);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::String::Type rccTaglibPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccTaglibPatchTryInit();
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccTaglibPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccTaglibPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ } else {
++ // Error or no-language configured: If Latin1ID3V2 is returned we normally will use the default unicode encoding unless Latin1 is selected by taglib
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.10/taglib/toolkit/rccpatch.h taglib-1.10-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.10/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.10-ds/taglib/toolkit/rccpatch.h 2015-11-26 23:03:07.060061249 +0100
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccTaglibPatchFree();
++void rccTaglibPatchInit();
++void rccTaglibPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccTaglibPatchGetLocaleType();
++TagLib::String::Type rccTaglibPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.10/taglib/toolkit/tstring.cpp taglib-1.10-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.10/taglib/toolkit/tstring.cpp 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/toolkit/tstring.cpp 2015-11-26 23:10:01.286853654 +0100
+@@ -29,6 +29,7 @@
+ #include <config.h>
+ #endif
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "tdebug.h"
+ #include "tstringlist.h"
+@@ -167,8 +168,11 @@
+ String::String(const std::string &s, Type t)
+ : d(new StringPrivate())
+ {
+- if(t == Latin1)
+- copyFromLatin1(s.c_str(), s.length());
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(&s[0], s.length(), true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(s.c_str(), s.length());
+ else {
+@@ -215,8 +219,11 @@
+ String::String(const char *s, Type t)
+ : d(new StringPrivate())
+ {
+- if(t == Latin1)
+- copyFromLatin1(s, ::strlen(s));
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(s, ::strlen(s), true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(s, ::strlen(s));
+ else {
+@@ -237,7 +244,10 @@
+ String::String(char c, Type t)
+ : d(new StringPrivate(1, static_cast<uchar>(c)))
+ {
+- if(t != Latin1 && t != UTF8) {
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t != Latin1 && t != Latin1ID3 && t != Latin1ID3V2 && t != UTF8) {
+ debug("String::String() -- char should not contain UTF16.");
+ }
+ }
+@@ -248,8 +258,11 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1)
+- copyFromLatin1(v.data(), v.size());
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(v.data(), v.size(), true, t);
+ else if(t == UTF8)
+ copyFromUTF8(v.data(), v.size());
+ else
+@@ -396,8 +409,38 @@
+
+ ByteVector String::data(Type t) const
+ {
+- switch(t)
+- {
++ ByteVector v;
++
++ if (t == Locale) {
++ // The source is either Unicode or real Latin1 (if rcc is bypassed)
++ std::string s = to8Bit(true);
++
++ // In case of UTF8 locale, this probably will return NULL (no recoding needed), but we will take UTF8 path in the next swtich
++ v = rccTaglibPatchRecodeOutput(s);
++ if (v.size()) return v;
++
++ t = rccTaglibPatchGetLocaleType();
++ }
++
++ switch(t) {
++ case Latin1ID3:
++ case Latin1ID3V2:
++ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeOutputID3(s, true);
++ if (v.size())
++ return v;
++
++ // we don't know if we got NULL because rcc is disabled (error) or UTF8 output is required
++ if ((t == Latin1ID3V2)&&(rccTaglibPatchGetID3Type() == UTF8)) {
++ v.setData(s.c_str(), s.length());
++ } else {
++ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
++ v.append(char(*it));
++ }
++ return v;
++ }
+ case Latin1:
+ {
+ ByteVector v(size(), 0);
+@@ -738,12 +781,30 @@
+ // private members
+ ////////////////////////////////////////////////////////////////////////////////
+
+-void String::copyFromLatin1(const char *s, size_t length)
++void String::copyFromLatin1(const char *s, size_t length, bool prepare, Type t)
+ {
+ d->data.resize(length);
+
+ for(size_t i = 0; i < length; ++i)
+ d->data[i] = static_cast<uchar>(s[i]);
++
++ // librcc conversation
++ if (prepare) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccTaglibPatchRecodeInput(s);
++
++ if (v.size()) {
++ copyFromUTF8(v.data(), v.size());
++ } else {
++ // We don't know if we got UTF-8 encoded string or either rcc is disable or something is failed,
++ // since standard applications are really expecting here Latin1, it is safe to just check if we have violations of UTF8
++ //if (Unicode::isLegalUTF8(s)) t = UTF8;
++ }
++ }
+ }
+
+ void String::copyFromUTF8(const char *s, size_t length)
+@@ -859,7 +920,33 @@
+
+ std::ostream &operator<<(std::ostream &s, const TagLib::String &str)
+ {
+- s << str.to8Bit();
++ TagLib::ByteVector bv = str.data(TagLib::String::Locale);
++ s << bv;
+ return s;
+ }
+
++TagLib::String::Type TagLib::String::ID3Type(int i)
++{
++ if(i == Latin1)
++ return Latin1ID3V2;
++ return Type(i);
++};
++
++TagLib::String::Type TagLib::String::ID3WType(Type type)
++{
++ Type rcc_type = rccTaglibPatchGetID3Type();
++ if((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)||(rcc_type == Latin1)) {
++ if(type == Latin1) return
++ rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++TagLib::String::Type TagLib::String::ID3RealType(Type type)
++{
++ if((type == Latin1ID3) || (type == Latin1ID3V2))
++ return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.10/taglib/toolkit/tstring.h taglib-1.10-ds/taglib/toolkit/tstring.h
+--- taglib-1.10/taglib/toolkit/tstring.h 2015-11-11 22:41:59.000000000 +0100
++++ taglib-1.10-ds/taglib/toolkit/tstring.h 2015-11-26 23:03:07.061061271 +0100
+@@ -96,6 +96,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3v2 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -117,6 +129,10 @@
+ */
+ UTF16LE = 4
+ };
++
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
+
+ /*!
+ * Constructs an empty String.
+@@ -519,7 +535,7 @@
+ * 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);
++ void copyFromLatin1(const char *s, size_t length, bool prepare = false, Type t = Latin1);
+
+ /*!
+ * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order)
+diff -dPNur taglib-1.10/taglib-1.10-ds-rusxmms.patch taglib-1.10-ds/taglib-1.10-ds-rusxmms.patch
+--- taglib-1.10/taglib-1.10-ds-rusxmms.patch 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.10-ds/taglib-1.10-ds-rusxmms.patch 2015-11-14 15:40:37.000000000 +0100
+@@ -0,0 +1,669 @@
++diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
++index 88980ea..e4f44d3 100644
++--- a/ConfigureChecks.cmake
+++++ b/ConfigureChecks.cmake
++@@ -201,6 +201,8 @@ if(NOT ZLIB_SOURCE)
++ endif()
++ endif()
++
+++SET(HAVE_LIBRCC 1)
+++
++ if(BUILD_TESTS)
++ find_package(CppUnit)
++ if(NOT CppUnit_FOUND)
++diff --git a/config.h.cmake b/config.h.cmake
++index ee0e67a..2abd49c 100644
++--- a/config.h.cmake
+++++ b/config.h.cmake
++@@ -25,4 +25,7 @@
++ /* Indicates whether debug messages are shown even in release mode */
++ #cmakedefine TRACE_IN_RELEASE 1
++
+++/* Defined if you have LibRCC from RusXMMS project */
+++#cmakedefine HAVE_LIBRCC 1
+++
++ #cmakedefine TESTS_DIR "@TESTS_DIR@"
++diff --git a/examples/tagreader_c.c b/examples/tagreader_c.c
++index 0436992..e0f17d8 100644
++--- a/examples/tagreader_c.c
+++++ b/examples/tagreader_c.c
++@@ -38,7 +38,7 @@ int main(int argc, char *argv[])
++ TagLib_Tag *tag;
++ const TagLib_AudioProperties *properties;
++
++- taglib_set_strings_unicode(FALSE);
+++ //taglib_set_strings_unicode(FALSE);
++
++ for(i = 1; i < argc; i++) {
++ printf("******************** \"%s\" ********************\n", argv[i]);
++diff --git a/examples/tagwriter.cpp b/examples/tagwriter.cpp
++index ed8b0d7..6a7a263 100644
++--- a/examples/tagwriter.cpp
+++++ b/examples/tagwriter.cpp
++@@ -115,7 +115,7 @@ int main(int argc, char *argv[])
++ if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
++
++ char field = argv[i][1];
++- TagLib::String value = argv[i + 1];
+++ TagLib::String value(argv[i + 1], TagLib::String::Locale);
++
++ TagLib::List<TagLib::FileRef>::ConstIterator it;
++ for(it = fileList.begin(); it != fileList.end(); ++it) {
++diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt
++index 73c1a2f..cd7ea22 100644
++--- a/taglib/CMakeLists.txt
+++++ b/taglib/CMakeLists.txt
++@@ -38,6 +38,7 @@ set(tag_HDRS
++ audioproperties.h
++ taglib_export.h
++ ${CMAKE_CURRENT_BINARY_DIR}/../taglib_config.h
+++ toolkit/rccpatch.h
++ toolkit/taglib.h
++ toolkit/tstring.h
++ toolkit/tlist.h
++@@ -291,6 +292,7 @@ set(xm_SRCS
++ )
++
++ set(toolkit_SRCS
+++ toolkit/rccpatch.cpp
++ toolkit/tstring.cpp
++ toolkit/tstringlist.cpp
++ toolkit/tbytevector.cpp
++@@ -337,7 +339,7 @@ set(tag_LIB_SRCS
++ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
++
++ if(ZLIB_FOUND)
++- target_link_libraries(tag ${ZLIB_LIBRARIES})
+++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
++ endif()
++
++ set_target_properties(tag PROPERTIES
++diff --git a/taglib/mpeg/id3v1/id3v1tag.cpp b/taglib/mpeg/id3v1/id3v1tag.cpp
++index 9fc8cfd..5352acc 100644
++--- a/taglib/mpeg/id3v1/id3v1tag.cpp
+++++ b/taglib/mpeg/id3v1/id3v1tag.cpp
++@@ -64,17 +64,18 @@ StringHandler::StringHandler()
++
++ String ID3v1::StringHandler::parse(const ByteVector &data) const
++ {
++- return String(data, String::Latin1).stripWhiteSpace();
+++ return String(data, String::Latin1ID3).stripWhiteSpace();
++ }
++
++ ByteVector ID3v1::StringHandler::render(const String &s) const
++ {
++ if(!s.isLatin1())
++ {
+++ if (String::ID3WType(String::Latin1) == String::Latin1)
++ return ByteVector();
++ }
++
++- return s.data(String::Latin1);
+++ return s.data(String::Latin1ID3);
++ }
++
++ ////////////////////////////////////////////////////////////////////////////////
++@@ -257,7 +258,7 @@ void ID3v1::Tag::parse(const ByteVector &data)
++ d->track = uchar(data[offset + 29]);
++ }
++ else
++- d->comment = data.mid(offset, 30);
+++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
++
++ offset += 30;
++
++diff --git a/taglib/mpeg/id3v2/frames/commentsframe.cpp b/taglib/mpeg/id3v2/frames/commentsframe.cpp
++index deaa9d9..c0aba2b 100644
++--- a/taglib/mpeg/id3v2/frames/commentsframe.cpp
+++++ b/taglib/mpeg/id3v2/frames/commentsframe.cpp
++@@ -150,10 +150,10 @@ void CommentsFrame::parseFields(const ByteVector &data)
++ return;
++ }
++
++- d->textEncoding = String::Type(data[0]);
+++ d->textEncoding = String::ID3Type(data[0]);
++ d->language = data.mid(1, 3);
++
++- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
+++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
++
++ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
++
++@@ -173,11 +173,13 @@ ByteVector CommentsFrame::renderFields() const
++ ByteVector v;
++
++ String::Type encoding = d->textEncoding;
+++
+++ encoding = String::ID3WType(encoding);
++
++ encoding = checkTextEncoding(d->description, encoding);
++ encoding = checkTextEncoding(d->text, encoding);
++
++- v.append(char(encoding));
+++ v.append(char(String::ID3RealType(encoding)));
++ v.append(d->language.size() == 3 ? d->language : "XXX");
++ v.append(d->description.data(encoding));
++ v.append(textDelimiter(encoding));
++diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
++index b77dd54..a4a7277 100644
++--- a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+++++ b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
++@@ -187,12 +187,12 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
++
++ // read the string data type (the first byte of the field data)
++
++- d->textEncoding = String::Type(data[0]);
+++ d->textEncoding = String::ID3Type(data[0]);
++
++ // split the byte array into chunks based on the string type (two byte delimiter
++ // for unicode encodings)
++
++- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
+++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
++
++ // build a small counter to strip nulls off the end of the field
++
++@@ -223,11 +223,14 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
++
++ ByteVector TextIdentificationFrame::renderFields() const
++ {
++- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
+++ String::Type encoding = d->textEncoding;
+++
+++ encoding = String::ID3WType(encoding);
+++ encoding = checkTextEncoding(d->fieldList, encoding);
++
++ ByteVector v;
++
++- v.append(char(encoding));
+++ v.append(char(String::ID3RealType(encoding)));
++
++ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
++
++diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp
++index bee5375..fea5ab3 100644
++--- a/taglib/mpeg/id3v2/id3v2frame.cpp
+++++ b/taglib/mpeg/id3v2/id3v2frame.cpp
++@@ -339,7 +339,7 @@ String::Type Frame::checkEncoding(const StringList &fields, String::Type encodin
++ if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4)
++ return String::UTF16;
++
++- if(encoding != String::Latin1)
+++ if((encoding != String::Latin1)&&(encoding != String::Latin1ID3V2))
++ return encoding;
++
++ for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
++diff --git a/taglib/toolkit/rccpatch.cpp b/taglib/toolkit/rccpatch.cpp
++new file mode 100644
++index 0000000..af99323
++--- /dev/null
+++++ b/taglib/toolkit/rccpatch.cpp
++@@ -0,0 +1,237 @@
+++#include <stdlib.h>
+++
+++#include <string>
+++#include "tstring.h"
+++#include "tbytevector.h"
+++
+++//#define RCC_DEBUG
+++
+++
+++#ifndef HAVE_LIBRCC
+++# include <config.h>
+++#endif
+++
+++#ifdef HAVE_LIBRCC
+++# ifdef RCC_DEBUG
+++# include <stdio.h>
+++# endif /* RCC_DEBUG */
+++# include <librcc.h>
+++# include <string.h>
+++#endif /* HAVE_LIBRCC */
+++
+++
+++#ifdef HAVE_LIBRCC
+++# define ID3_CLASS 0
+++# define ID3V2_CLASS 1
+++# define UTF_CLASS 2
+++# define OUT_CLASS 3
+++static rcc_class classes[] = {
+++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
+++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
+++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
+++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
+++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
+++};
+++
+++static int rcc_initialized = 0;
+++
+++static rcc_context ctx = NULL;
+++#endif /* HAVE_LIBRCC */
+++
+++
+++void rccTaglibPatchFree() {
+++#ifdef HAVE_LIBRCC
+++ if (rcc_initialized) {
+++ rccFree();
+++ rcc_initialized = 0;
+++ }
+++#endif /* HAVE_LIBRCC */
+++}
+++
+++void rccTaglibPatchInit() {
+++#ifdef HAVE_LIBRCC
+++ if (rcc_initialized) return;
+++ rccInit();
+++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
+++ rccLoad(NULL, "xmms");
+++ rccInitDb4(NULL, NULL, 0);
+++ rcc_initialized = 1;
+++#endif /* HAVE_LIBRCC */
+++}
+++
+++void rccTaglibPatchSetContext(void *newctx) {
+++#ifdef HAVE_LIBRCC
+++ if (newctx) {
+++ ctx = (rcc_context)newctx;
+++ rcc_initialized = 1;
+++ }
+++#endif /* HAVE_LIBRCC */
+++}
+++
+++static void rccTaglibPatchTryInit() {
+++#ifdef HAVE_LIBRCC
+++ if (!rcc_initialized) {
+++ rccTaglibPatchInit();
+++ if (rcc_initialized) atexit(rccTaglibPatchFree);
+++ }
+++#endif /* HAVE_LIBRCC */
+++}
+++
+++
+++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s) {
+++ TagLib::ByteVector v;
+++#ifdef HAVE_LIBRCC
+++ size_t rlen;
+++ char *res;
+++
+++ rccTaglibPatchTryInit();
+++
+++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
+++#ifdef RCC_DEBUG
+++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
+++ if (*c > 127) {
+++ printf(" Output: %s - %s\n", s.c_str(), res?res:"null");
+++ break;
+++ }
+++ }
+++#endif /* RCC_DEBUG */
+++
+++ if (res) v.setData(res, rlen);
+++ else v.setData("", 0);
+++ //v.setData(s.c_str(), s.length());
+++
+++ return v;
+++#else
+++ v.setData("", 0);
+++
+++ return v;
+++#endif /* HAVE_LIBRCC */
+++}
+++
+++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
+++ TagLib::ByteVector v;
+++#ifdef HAVE_LIBRCC
+++ size_t rlen;
+++ char *res;
+++
+++ rccTaglibPatchTryInit();
+++
+++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
+++#ifdef RCC_DEBUG
+++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
+++ if (*c > 127) {
+++ printf(" OutputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
+++ break;
+++ }
+++ }
+++#endif /* RCC_DEBUG */
+++
+++ if (res) v.setData(res, rlen);
+++ else v.setData("", 0);
+++ //v.setData(s.c_str(), s.length());
+++
+++ return v;
+++#else
+++ v.setData("", 0);
+++
+++ return v;
+++#endif /* HAVE_LIBRCC */
+++}
+++
+++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s) {
+++ TagLib::ByteVector v;
+++#ifdef HAVE_LIBRCC
+++ size_t rlen;
+++ char *res;
+++
+++ rccTaglibPatchTryInit();
+++
+++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
+++#ifdef RCC_DEBUG
+++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
+++ if (*c > 127) {
+++ printf(" Input: %s - %s\n", s.c_str(), res?res:"null");
+++ break;
+++ }
+++ }
+++#endif /* RCC_DEBUG */
+++
+++ if (res) v.setData(res, rlen);
+++ else
+++#endif /* HAVE_LIBRCC */
+++ v.setData("", 0);
+++
+++ return v;
+++}
+++
+++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false) {
+++ TagLib::ByteVector v;
+++#ifdef HAVE_LIBRCC
+++ size_t rlen;
+++ char *res;
+++
+++ rccTaglibPatchTryInit();
+++
+++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
+++#ifdef RCC_DEBUG
+++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
+++ if (*c > 127) {
+++ printf(" InputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
+++ break;
+++ }
+++ }
+++#endif /* RCC_DEBUG */
+++ if (res) v.setData(res, rlen + 1);
+++ else
+++#endif /* HAVE_LIBRCC */
+++ v.setData("", 0);
+++
+++ return v;
+++}
+++
+++TagLib::String::Type rccTaglibPatchGetLocaleType() {
+++#ifdef HAVE_LIBRCC
+++ size_t len;
+++ char charset[32];
+++
+++ rccTaglibPatchTryInit();
+++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
+++ if (!strncmp(charset, "UTF", 3)) {
+++ len = strlen(charset);
+++
+++ if (charset[len-1]=='8') return TagLib::String::UTF8;
+++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
+++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
+++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
+++ }
+++ return TagLib::String::Latin1;
+++ }
+++#endif /* HAVE_LIBRCC */
+++ return TagLib::String::UTF8;
+++}
+++
+++TagLib::String::Type rccTaglibPatchGetID3Type() {
+++#ifdef HAVE_LIBRCC
+++ size_t len;
+++ const char *charset;
+++
+++ rccTaglibPatchTryInit();
+++
+++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
+++ if (charset) {
+++ if (!strncmp(charset, "UTF", 3)) {
+++ len = strlen(charset);
+++
+++ if (charset[len-1]=='8') return TagLib::String::UTF8;
+++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
+++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
+++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
+++ }
+++ return TagLib::String::Latin1ID3V2;
+++ } else {
+++ // Error or no-language configured: If Latin1ID3V2 is returned we normally will use the default unicode encoding unless Latin1 is selected by taglib
+++ return TagLib::String::Latin1ID3V2;
+++ }
+++#endif /* HAVE_LIBRCC */
+++ return TagLib::String::Latin1;
+++}
++diff --git a/taglib/toolkit/rccpatch.h b/taglib/toolkit/rccpatch.h
++new file mode 100644
++index 0000000..31f4410
++--- /dev/null
+++++ b/taglib/toolkit/rccpatch.h
++@@ -0,0 +1,20 @@
+++#ifndef _RCC_PATCH_H
+++#define _RCC_PATCH_H
+++
+++#include <string.h>
+++#include "tstring.h"
+++#include "tbytevector.h"
+++
+++void rccTaglibPatchFree();
+++void rccTaglibPatchInit();
+++void rccTaglibPatchSetContext(void *newctx);
+++
+++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s);
+++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s);
+++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false);
+++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false);
+++
+++TagLib::String::Type rccTaglibPatchGetLocaleType();
+++TagLib::String::Type rccTaglibPatchGetID3Type();
+++
+++#endif /* _RCC_PATCH_H */
++diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp
++index 258e1fc..70ff160 100644
++--- a/taglib/toolkit/tstring.cpp
+++++ b/taglib/toolkit/tstring.cpp
++@@ -29,6 +29,7 @@
++ #include <config.h>
++ #endif
++
+++#include "rccpatch.h"
++ #include "tstring.h"
++ #include "tdebug.h"
++ #include "tstringlist.h"
++@@ -167,8 +168,11 @@ String::String(const String &s)
++ String::String(const std::string &s, Type t)
++ : d(new StringPrivate())
++ {
++- if(t == Latin1)
++- copyFromLatin1(s.c_str(), s.length());
+++ if(t == Locale)
+++ t = rccTaglibPatchGetLocaleType();
+++
+++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
+++ copyFromLatin1(&s[0], s.length(), true, t);
++ else if(t == String::UTF8)
++ copyFromUTF8(s.c_str(), s.length());
++ else {
++@@ -215,8 +219,11 @@ String::String(const wchar_t *s, Type t)
++ String::String(const char *s, Type t)
++ : d(new StringPrivate())
++ {
++- if(t == Latin1)
++- copyFromLatin1(s, ::strlen(s));
+++ if(t == Locale)
+++ t = rccTaglibPatchGetLocaleType();
+++
+++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
+++ copyFromLatin1(s, ::strlen(s), true, t);
++ else if(t == String::UTF8)
++ copyFromUTF8(s, ::strlen(s));
++ else {
++@@ -248,8 +255,11 @@ String::String(const ByteVector &v, Type t)
++ if(v.isEmpty())
++ return;
++
++- if(t == Latin1)
++- copyFromLatin1(v.data(), v.size());
+++ if(t == Locale)
+++ t = rccTaglibPatchGetLocaleType();
+++
+++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
+++ copyFromLatin1(v.data(), v.size(), true, t);
++ else if(t == UTF8)
++ copyFromUTF8(v.data(), v.size());
++ else
++@@ -396,8 +406,38 @@ bool String::isNull() const
++
++ ByteVector String::data(Type t) const
++ {
++- switch(t)
++- {
+++ ByteVector v;
+++
+++ if (t == Locale) {
+++ // The source is either Unicode or real Latin1 (if rcc is bypassed)
+++ std::string s = to8Bit(true);
+++
+++ // In case of UTF8 locale, this probably will return NULL (no recoding needed), but we will take UTF8 path in the next swtich
+++ v = rccTaglibPatchRecodeOutput(s);
+++ if (v.size()) return v;
+++
+++ t = rccTaglibPatchGetLocaleType();
+++ }
+++
+++ switch(t) {
+++ case Latin1ID3:
+++ case Latin1ID3V2:
+++ {
+++ std::string s = to8Bit(true);
+++ if (t == Latin1ID3) v = rccTaglibPatchRecodeOutputID3(s, false);
+++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeOutputID3(s, true);
+++ if (v.size())
+++ return v;
+++
+++ // we don't know if we got NULL because rcc is disabled (error) or UTF8 output is required
+++ if ((t == Latin1ID3V2)&&(rccTaglibPatchGetID3Type() == UTF8)) {
+++ v.setData(s.c_str(), s.length());
+++ } else {
+++ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+++ v.append(char(*it));
+++ }
+++ return v;
+++ }
++ case Latin1:
++ {
++ ByteVector v(size(), 0);
++@@ -738,12 +778,30 @@ void String::detach()
++ // private members
++ ////////////////////////////////////////////////////////////////////////////////
++
++-void String::copyFromLatin1(const char *s, size_t length)
+++void String::copyFromLatin1(const char *s, size_t length, bool prepare, Type t)
++ {
++ d->data.resize(length);
++
++ for(size_t i = 0; i < length; ++i)
++ d->data[i] = static_cast<uchar>(s[i]);
+++
+++ // librcc conversation
+++ if (prepare) {
+++ std::string s = to8Bit(false);
+++ ByteVector v;
+++
+++ if (t == Latin1ID3) v = rccTaglibPatchRecodeInputID3(s, false);
+++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeInputID3(s, true);
+++ else /* Latin1 converted from Locale */ v = rccTaglibPatchRecodeInput(s);
+++
+++ if (v.size()) {
+++ copyFromUTF8(v.data(), v.size());
+++ } else {
+++ // We don't know if we got UTF-8 encoded string or either rcc is disable or something is failed,
+++ // since standard applications are really expecting here Latin1, it is safe to just check if we have violations of UTF8
+++ //if (Unicode::isLegalUTF8(s)) t = UTF8;
+++ }
+++ }
++ }
++
++ void String::copyFromUTF8(const char *s, size_t length)
++@@ -859,7 +917,33 @@ const TagLib::String operator+(const TagLib::String &s1, const char *s2)
++
++ std::ostream &operator<<(std::ostream &s, const TagLib::String &str)
++ {
++- s << str.to8Bit();
+++ TagLib::ByteVector bv = str.data(TagLib::String::Locale);
+++ s << bv;
++ return s;
++ }
++
+++TagLib::String::Type TagLib::String::ID3Type(int i)
+++{
+++ if(i == Latin1)
+++ return Latin1ID3V2;
+++ return Type(i);
+++};
+++
+++TagLib::String::Type TagLib::String::ID3WType(Type type)
+++{
+++ Type rcc_type = rccTaglibPatchGetID3Type();
+++ if((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)||(rcc_type == Latin1)) {
+++ if(type == Latin1) return
+++ rcc_type;
+++ return type;
+++ }
+++
+++ return rcc_type;
+++};
+++
+++TagLib::String::Type TagLib::String::ID3RealType(Type type)
+++{
+++ if((type == Latin1ID3) || (type == Latin1ID3V2))
+++ return Latin1;
+++ return type;
+++}
++diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h
++index 8b73988..8efca25 100644
++--- a/taglib/toolkit/tstring.h
+++++ b/taglib/toolkit/tstring.h
++@@ -96,6 +96,18 @@ namespace TagLib {
++ */
++ enum Type {
++ /*!
+++ * Determine using current locale settings
+++ */
+++ Locale = -1,
+++ /*!
+++ * Latin1 for ID3 tags.
+++ */
+++ Latin1ID3 = 65,
+++ /*!
+++ * Latin1 for ID3v2 tags.
+++ */
+++ Latin1ID3V2 = 66,
+++ /*!
++ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
++ */
++ Latin1 = 0,
++@@ -117,6 +129,10 @@ namespace TagLib {
++ */
++ UTF16LE = 4
++ };
+++
+++ static Type ID3Type(int i);
+++ static Type ID3WType(Type type);
+++ static Type ID3RealType(Type type);
++
++ /*!
++ * Constructs an empty String.
++@@ -519,7 +535,7 @@ namespace TagLib {
++ * 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);
+++ void copyFromLatin1(const char *s, size_t length, bool prepare = false, Type t = Latin1);
++
++ /*!
++ * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order)
diff --git a/patches/taglib/taglib-1.11-ds-rusxmms.patch b/patches/taglib/taglib-1.11-ds-rusxmms.patch
new file mode 100644
index 0000000..9f777c8
--- /dev/null
+++ b/patches/taglib/taglib-1.11-ds-rusxmms.patch
@@ -0,0 +1,684 @@
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/config.h.cmake taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/config.h.cmake
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/config.h.cmake 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/config.h.cmake 2019-09-01 08:32:29.569443643 +0200
+@@ -30,6 +30,9 @@
+ /* Indicates whether debug messages are shown even in release mode */
+ #cmakedefine TRACE_IN_RELEASE 1
+
++/* Defined if you have LibRCC from RusXMMS project */
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine TESTS_DIR "@TESTS_DIR@"
+
+ #endif
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/ConfigureChecks.cmake taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/ConfigureChecks.cmake
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/ConfigureChecks.cmake 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/ConfigureChecks.cmake 2019-09-01 08:32:29.577443787 +0200
+@@ -213,3 +213,5 @@
+ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
+ set(PLATFORM WINRT 1)
+ endif()
++
++SET(HAVE_LIBRCC 1)
+\ No newline at end of file
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/examples/tagreader_c.c taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/examples/tagreader_c.c
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/examples/tagreader_c.c 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/examples/tagreader_c.c 2019-09-01 08:32:29.577443787 +0200
+@@ -38,7 +38,7 @@
+ TagLib_Tag *tag;
+ const TagLib_AudioProperties *properties;
+
+- taglib_set_strings_unicode(FALSE);
++ //taglib_set_strings_unicode(FALSE);
+
+ for(i = 1; i < argc; i++) {
+ printf("******************** \"%s\" ********************\n", argv[i]);
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/examples/tagwriter.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/examples/tagwriter.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/examples/tagwriter.cpp 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/examples/tagwriter.cpp 2019-09-01 08:32:29.577443787 +0200
+@@ -115,7 +115,7 @@
+ if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
+
+ char field = argv[i][1];
+- TagLib::String value = argv[i + 1];
++ TagLib::String value(argv[i + 1], TagLib::String::Locale);
+
+ TagLib::List<TagLib::FileRef>::ConstIterator it;
+ for(it = fileList.begin(); it != fileList.end(); ++it) {
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/CMakeLists.txt taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/CMakeLists.txt
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/CMakeLists.txt 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/CMakeLists.txt 2019-09-01 08:32:29.577443787 +0200
+@@ -41,6 +41,7 @@
+ audioproperties.h
+ taglib_export.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../taglib_config.h
++ toolkit/rccpatch.h
+ toolkit/taglib.h
+ toolkit/tstring.h
+ toolkit/tlist.h
+@@ -312,6 +313,7 @@
+ )
+
+ set(toolkit_SRCS
++ toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -354,7 +356,9 @@
+ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
+
+ if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
+- target_link_libraries(tag ${ZLIB_LIBRARIES})
++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
++else ()
++ target_link_libraries(tag rcc)
+ endif()
+
+ set_target_properties(tag PROPERTIES
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v1/id3v1tag.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v1/id3v1tag.cpp 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2019-09-01 08:32:29.577443787 +0200
+@@ -69,15 +69,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+- if(s.isLatin1())
+- return s.data(String::Latin1);
+- else
++ if(!s.isLatin1())
++ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
++ }
++
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -262,7 +265,7 @@
+ d->track = static_cast<unsigned char>(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v2/frames/commentsframe.cpp 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2019-09-01 08:32:29.578443805 +0200
+@@ -150,10 +150,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -173,11 +173,13 @@
+ ByteVector v;
+
+ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
+
+ encoding = checkTextEncoding(d->description, encoding);
+ encoding = checkTextEncoding(d->text, encoding);
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2019-09-01 08:32:29.578443805 +0200
+@@ -191,12 +191,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -227,11 +227,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkTextEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v2/id3v2frame.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v2/id3v2frame.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/mpeg/id3v2/id3v2frame.cpp 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/mpeg/id3v2/id3v2frame.cpp 2019-09-01 08:32:29.578443805 +0200
+@@ -297,7 +297,7 @@
+ if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4)
+ return String::UTF16;
+
+- if(encoding != String::Latin1)
++ if((encoding != String::Latin1)&&(encoding != String::Latin1ID3V2))
+ return encoding;
+
+ for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/rccpatch.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/rccpatch.cpp 2019-09-01 08:32:29.578443805 +0200
+@@ -0,0 +1,237 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++//#define RCC_DEBUG
++
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# ifdef RCC_DEBUG
++# include <stdio.h>
++# endif /* RCC_DEBUG */
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccTaglibPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccTaglibPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccTaglibPatchInit();
++ if (rcc_initialized) atexit(rccTaglibPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Output: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" OutputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Input: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" InputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++ if (res) v.setData(res, rlen + 1);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::String::Type rccTaglibPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccTaglibPatchTryInit();
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccTaglibPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccTaglibPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ } else {
++ // Error or no-language configured: If Latin1ID3V2 is returned we normally will use the default unicode encoding unless Latin1 is selected by taglib
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/rccpatch.h taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/rccpatch.h
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/rccpatch.h 2019-09-01 08:32:29.578443805 +0200
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccTaglibPatchFree();
++void rccTaglibPatchInit();
++void rccTaglibPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccTaglibPatchGetLocaleType();
++TagLib::String::Type rccTaglibPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/tstring.cpp taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/tstring.cpp
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/tstring.cpp 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/tstring.cpp 2019-09-01 08:27:18.763821274 +0200
+@@ -33,6 +33,7 @@
+ #include <trefcounter.h>
+ #include <tutils.h>
+
++#include "rccpatch.h"
+ #include "tstring.h"
+
+ namespace
+@@ -48,16 +49,6 @@
+ return String::UTF16BE;
+ }
+
+- // 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)
+@@ -73,6 +64,36 @@
+ debug("String::copyFromUTF8() - UTF8-CPP error: " + message);
+ data.clear();
+ }
++
++ }
++
++ // 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, bool prepare, String::Type t)
++ {
++ // librcc conversation
++ if (prepare) {
++ ByteVector v;
++ std::string std_s(s);
++
++ if (t == String::Latin1ID3) v = rccTaglibPatchRecodeInputID3(std_s, false);
++ else if (t == String::Latin1ID3V2) v = rccTaglibPatchRecodeInputID3(std_s, true);
++ else /* Latin1 converted from Locale */ v = rccTaglibPatchRecodeInput(std_s);
++
++ if (v.size()) {
++ copyFromUTF8(data, v.data(), v.size());
++ return;
++ } else {
++ // We don't know if we got UTF-8 encoded string or either rcc is disable or something is failed,
++ // since standard applications are really expecting here Latin1, it is safe to just check if we have violations of UTF8
++ //if (Unicode::isLegalUTF8(s)) t = UTF8;
++ }
++ }
++
++ data.resize(length);
++
++ for(size_t i = 0; i < length; ++i)
++ data[i] = static_cast<unsigned char>(s[i]);
+ }
+
+ // Helper functions to read a UTF-16 character from an array.
+@@ -175,8 +196,11 @@
+ String::String(const std::string &s, Type t) :
+ d(new StringPrivate())
+ {
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
+ if(t == Latin1)
+- copyFromLatin1(d->data, s.c_str(), s.length());
++ copyFromLatin1(d->data, s.c_str(), s.length(), true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(d->data, s.c_str(), s.length());
+ else {
+@@ -223,8 +247,11 @@
+ String::String(const char *s, Type t) :
+ d(new StringPrivate())
+ {
+- if(t == Latin1)
+- copyFromLatin1(d->data, s, ::strlen(s));
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(d->data, s, ::strlen(s), true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(d->data, s, ::strlen(s));
+ else {
+@@ -245,8 +272,11 @@
+ String::String(char c, Type t) :
+ d(new StringPrivate())
+ {
+- if(t == Latin1)
+- copyFromLatin1(d->data, &c, 1);
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(d->data, &c, 1, true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(d->data, &c, 1);
+ else {
+@@ -260,8 +290,11 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1)
+- copyFromLatin1(d->data, v.data(), v.size());
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(d->data, v.data(), v.size(), true, t);
+ else if(t == UTF8)
+ copyFromUTF8(d->data, v.data(), v.size());
+ else
+@@ -416,8 +449,38 @@
+
+ ByteVector String::data(Type t) const
+ {
+- switch(t)
+- {
++ ByteVector v;
++
++ if (t == Locale) {
++ // The source is either Unicode or real Latin1 (if rcc is bypassed)
++ std::string s = to8Bit(true);
++
++ // In case of UTF8 locale, this probably will return NULL (no recoding needed), but we will take UTF8 path in the next swtich
++ v = rccTaglibPatchRecodeOutput(s);
++ if (v.size()) return v;
++
++ t = rccTaglibPatchGetLocaleType();
++ }
++
++ switch(t) {
++ case Latin1ID3:
++ case Latin1ID3V2:
++ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeOutputID3(s, true);
++ if (v.size())
++ return v;
++
++ // we don't know if we got NULL because rcc is disabled (error) or UTF8 output is required
++ if ((t == Latin1ID3V2)&&(rccTaglibPatchGetID3Type() == UTF8)) {
++ v.setData(s.c_str(), s.length());
++ } else {
++ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
++ v.append(char(*it));
++ }
++ return v;
++ }
+ case Latin1:
+ {
+ ByteVector v(size(), 0);
+@@ -741,7 +804,33 @@
+
+ std::ostream &operator<<(std::ostream &s, const TagLib::String &str)
+ {
+- s << str.to8Bit();
++ TagLib::ByteVector bv = str.data(TagLib::String::Locale);
++ s << bv;
+ return s;
+ }
+
++TagLib::String::Type TagLib::String::ID3Type(int i)
++{
++ if(i == Latin1)
++ return Latin1ID3V2;
++ return Type(i);
++};
++
++TagLib::String::Type TagLib::String::ID3WType(Type type)
++{
++ Type rcc_type = rccTaglibPatchGetID3Type();
++ if((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)||(rcc_type == Latin1)) {
++ if(type == Latin1) return
++ rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++TagLib::String::Type TagLib::String::ID3RealType(Type type)
++{
++ if((type == Latin1ID3) || (type == Latin1ID3V2))
++ return Latin1;
++ return type;
++}
+diff -dPNur taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/tstring.h taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/tstring.h
+--- taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c/taglib/toolkit/tstring.h 2018-10-28 14:43:45.000000000 +0100
++++ taglib-5cb589a5b82c13ba8f0542e5e79629da7645cb3c-ds/taglib/toolkit/tstring.h 2019-09-01 08:32:29.579443823 +0200
+@@ -96,6 +96,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3v2 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -117,6 +129,10 @@
+ */
+ UTF16LE = 4
+ };
++
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
+
+ /*!
+ * Constructs an empty String.
diff --git a/patches/taglib/taglib-1.4-ds-rusxmms.patch b/patches/taglib/taglib-1.4-ds-rusxmms.patch
new file mode 100644
index 0000000..5b67c7c
--- /dev/null
+++ b/patches/taglib/taglib-1.4-ds-rusxmms.patch
@@ -0,0 +1,504 @@
+diff -dPNur taglib-1.4/configure.in taglib-1.4-new/configure.in
+--- taglib-1.4/configure.in 2005-07-27 02:45:33.000000000 +0200
++++ taglib-1.4-new/configure.in 2005-09-16 01:45:30.000000000 +0200
+@@ -98,6 +98,20 @@
+
+ AC_SUBST(AUTODIRS)
+
++AC_CHECK_LIB(rcc, rccInit,[
++ AC_CHECK_HEADERS(librcc.h,[
++ LIBRCC_LIBS="-lrcc"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
++
+ dnl =======================================================
+ dnl FILE: ./taglib/configure.in.in
+ dnl =======================================================
+diff -dPNur taglib-1.4/configure.in.in taglib-1.4-new/configure.in.in
+--- taglib-1.4/configure.in.in 2005-07-23 23:43:58.000000000 +0200
++++ taglib-1.4-new/configure.in.in 2005-09-16 01:45:30.000000000 +0200
+@@ -94,3 +94,16 @@
+
+ AC_SUBST(AUTODIRS)
+
++AC_CHECK_LIB(rcc, rccInit,[
++ AC_CHECK_HEADERS(librcc.h,[
++ LIBRCC_LIBS="-lrcc"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
+diff -dPNur taglib-1.4/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.4-new/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.4/taglib/mpeg/id3v1/id3v1tag.cpp 2005-05-17 22:17:16.000000000 +0200
++++ taglib-1.4-new/taglib/mpeg/id3v1/id3v1tag.cpp 2005-09-16 01:46:37.000000000 +0200
+@@ -55,12 +55,12 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1);
++ return String(data, String::Latin1ID3);
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -231,7 +231,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.4/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.4-new/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.4/taglib/mpeg/id3v2/frames/commentsframe.cpp 2005-07-25 23:16:32.000000000 +0200
++++ taglib-1.4-new/taglib/mpeg/id3v2/frames/commentsframe.cpp 2005-09-16 01:45:30.000000000 +0200
+@@ -115,7 +115,7 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+ int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
+@@ -131,12 +131,13 @@
+ ByteVector CommentsFrame::renderFields() const
+ {
+ ByteVector v;
++ String::Type textEncoding = String::ID3WType(d->textEncoding);
+
+- v.append(char(d->textEncoding));
++ v.append(char(textEncoding));
+ v.append(d->language.size() == 3 ? d->language : " ");
+- v.append(d->description.data(d->textEncoding));
+- v.append(textDelimiter(d->textEncoding));
+- v.append(d->text.data(d->textEncoding));
++ v.append(d->description.data(textEncoding));
++ v.append(textDelimiter(textEncoding));
++ v.append(d->text.data(textEncoding));
+
+ return v;
+ }
+diff -dPNur taglib-1.4/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.4-new/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.4/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2005-05-17 22:17:26.000000000 +0200
++++ taglib-1.4-new/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2005-09-16 01:45:30.000000000 +0200
+@@ -96,7 +96,7 @@
+ {
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+@@ -121,8 +121,9 @@
+ ByteVector v;
+
+ if(d->fieldList.size() > 0) {
++ String::Type textEncoding = String::ID3WType(d->textEncoding);
+
+- v.append(char(d->textEncoding));
++ v.append(char(textEncoding));
+
+ for(StringList::Iterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+@@ -131,9 +132,9 @@
+ // encoding.
+
+ if(it != d->fieldList.begin())
+- v.append(textDelimiter(d->textEncoding));
++ v.append(textDelimiter(textEncoding));
+
+- v.append((*it).data(d->textEncoding));
++ v.append((*it).data(textEncoding));
+ }
+ }
+
+diff -dPNur taglib-1.4/taglib/toolkit/Makefile.am taglib-1.4-new/taglib/toolkit/Makefile.am
+--- taglib-1.4/taglib/toolkit/Makefile.am 2005-07-25 23:16:32.000000000 +0200
++++ taglib-1.4-new/taglib/toolkit/Makefile.am 2005-09-16 01:45:30.000000000 +0200
+@@ -1,12 +1,15 @@
+-INCLUDES = $(all_includes)
++INCLUDES = $(all_includes) @LIBRCC_INCLUDES@
++libtoolkit_la_LDFLAGS = @LIBRCC_LIBS@
+
+ noinst_LTLIBRARIES = libtoolkit.la
+
+ libtoolkit_la_SOURCES = \
++ rccpatch.cpp \
+ tstring.cpp tstringlist.cpp tbytevector.cpp \
+ tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp
+
+ taglib_include_HEADERS = \
++ rccpatch.h \
+ taglib.h tstring.h tlist.h tlist.tcc tstringlist.h \
+ tbytevector.h tbytevectorlist.h tfile.h \
+ tmap.h tmap.tcc
+diff -dPNur taglib-1.4/taglib/toolkit/rccpatch.cpp taglib-1.4-new/taglib/toolkit/rccpatch.cpp
+--- taglib-1.4/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.4-new/taglib/toolkit/rccpatch.cpp 2005-09-16 01:45:30.000000000 +0200
+@@ -0,0 +1,202 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++char *rccPatchRecode(const char *str, size_t len, size_t *rlen) {
++#ifdef HAVE_LIBRCC
++ rccPatchTryInit();
++
++ return rccSizedRecode(ctx, ID3_CLASS, OUT_CLASS, str, len, rlen);
++#else
++ return NULL;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.4/taglib/toolkit/rccpatch.h taglib-1.4-new/taglib/toolkit/rccpatch.h
+--- taglib-1.4/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.4-new/taglib/toolkit/rccpatch.h 2005-09-16 01:45:30.000000000 +0200
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.4/taglib/toolkit/tstring.cpp taglib-1.4-new/taglib/toolkit/tstring.cpp
+--- taglib-1.4/taglib/toolkit/tstring.cpp 2005-07-25 23:31:15.000000000 +0200
++++ taglib-1.4-new/taglib/toolkit/tstring.cpp 2005-09-16 01:45:30.000000000 +0200
+@@ -19,6 +19,7 @@
+ * USA *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -161,7 +162,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -334,10 +335,18 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
++ case Latin1ID3:
+ case Latin1:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s);
++ else v = rccPatchRecodeOutput(s);
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -649,6 +658,30 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s);
++ else v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ }
++
++ t = UTF8;
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -738,6 +771,17 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ if ((type == Latin1)||(type == Latin1ID3)) return rccPatchGetID3Type();
++ return type;
++};
+diff -dPNur taglib-1.4/taglib/toolkit/tstring.h taglib-1.4-new/taglib/toolkit/tstring.h
+--- taglib-1.4/taglib/toolkit/tstring.h 2005-07-25 23:55:14.000000000 +0200
++++ taglib-1.4-new/taglib/toolkit/tstring.h 2005-09-16 01:45:30.000000000 +0200
+@@ -75,6 +75,14 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 5,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -97,6 +105,9 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.5-ds-rusxmms.patch b/patches/taglib/taglib-1.5-ds-rusxmms.patch
new file mode 100644
index 0000000..0d80fb5
--- /dev/null
+++ b/patches/taglib/taglib-1.5-ds-rusxmms.patch
@@ -0,0 +1,584 @@
+diff -dPNur taglib-1.5/config-taglib.h.cmake taglib-1.5-ds/config-taglib.h.cmake
+--- taglib-1.5/config-taglib.h.cmake 2008-01-11 01:56:23.000000000 +0100
++++ taglib-1.5-ds/config-taglib.h.cmake 2008-11-20 15:58:31.000000000 +0100
+@@ -6,4 +6,6 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+diff -dPNur taglib-1.5/ConfigureChecks.cmake taglib-1.5-ds/ConfigureChecks.cmake
+--- taglib-1.5/ConfigureChecks.cmake 2008-01-11 01:56:23.000000000 +0100
++++ taglib-1.5-ds/ConfigureChecks.cmake 2008-11-20 15:58:31.000000000 +0100
+@@ -14,6 +14,8 @@
+ #check for libz using the cmake supplied FindZLIB.cmake
+ FIND_PACKAGE(ZLIB)
+
++SET(HAVE_LIBRCC 1)
++
+ IF(ZLIB_FOUND)
+ SET(HAVE_ZLIB 1)
+ ELSE(ZLIB_FOUND)
+diff -dPNur taglib-1.5/configure.in taglib-1.5-ds/configure.in
+--- taglib-1.5/configure.in 2008-02-13 00:53:05.000000000 +0100
++++ taglib-1.5-ds/configure.in 2008-11-20 15:24:19.000000000 +0100
+@@ -98,6 +98,20 @@
+
+ AC_SUBST(AUTODIRS)
+
++AC_CHECK_LIB(rcc, rccInit,[
++ AC_CHECK_HEADERS(librcc.h,[
++ LIBRCC_LIBS="-lrcc"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
++
+ #AM_INIT_AUTOMAKE(taglib,1.0)
+ dnl don't remove the below
+ dnl AC_OUTPUT(taglib-config)
+diff -dPNur taglib-1.5/configure.in.in taglib-1.5-ds/configure.in.in
+--- taglib-1.5/configure.in.in 2008-01-30 02:34:06.000000000 +0100
++++ taglib-1.5-ds/configure.in.in 2008-11-20 15:24:19.000000000 +0100
+@@ -94,6 +94,21 @@
+
+ AC_SUBST(AUTODIRS)
+
++AC_CHECK_LIB(rcc, rccInit,[
++ AC_CHECK_HEADERS(librcc.h,[
++ LIBRCC_LIBS="-lrcc"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
++
++
+ #AM_INIT_AUTOMAKE(taglib,1.0)
+ dnl don't remove the below
+ dnl AC_OUTPUT(taglib-config)
+diff -dPNur taglib-1.5/taglib/CMakeLists.txt taglib-1.5-ds/taglib/CMakeLists.txt
+--- taglib-1.5/taglib/CMakeLists.txt 2008-02-12 05:15:20.000000000 +0100
++++ taglib-1.5-ds/taglib/CMakeLists.txt 2008-11-20 15:58:31.000000000 +0100
+@@ -119,6 +119,7 @@
+ )
+
+ SET(toolkit_SRCS
++toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -140,7 +141,7 @@
+
+ ADD_LIBRARY(tag SHARED ${tag_LIB_SRCS})
+
+-TARGET_LINK_LIBRARIES(tag )
++TARGET_LINK_LIBRARIES(tag rcc)
+ if(ZLIB_FOUND)
+ TARGET_LINK_LIBRARIES(tag ${ZLIB_LIBRARIES})
+ endif(ZLIB_FOUND)
+diff -dPNur taglib-1.5/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.5-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.5/taglib/mpeg/id3v1/id3v1tag.cpp 2008-02-04 16:14:45.000000000 +0100
++++ taglib-1.5-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2008-11-20 15:24:19.000000000 +0100
+@@ -59,17 +59,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -240,7 +241,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.5/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.5-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.5/taglib/mpeg/id3v2/frames/commentsframe.cpp 2008-02-04 16:14:46.000000000 +0100
++++ taglib-1.5-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2008-11-20 15:24:19.000000000 +0100
+@@ -136,10 +136,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = d->textEncoding == (String::Latin1 || String::Latin1ID3 || String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -155,10 +155,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkEncoding(d->description, encoding);
+ encoding = checkEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.5/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.5-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.5/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2008-02-04 16:14:46.000000000 +0100
++++ taglib-1.5-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2008-11-20 15:24:19.000000000 +0100
+@@ -105,12 +105,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -139,11 +139,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.5/taglib/toolkit/CMakeLists.txt taglib-1.5-ds/taglib/toolkit/CMakeLists.txt
+--- taglib-1.5/taglib/toolkit/CMakeLists.txt 2008-01-11 01:54:01.000000000 +0100
++++ taglib-1.5-ds/taglib/toolkit/CMakeLists.txt 2008-11-20 15:58:31.000000000 +0100
+@@ -1 +1 @@
+-INSTALL( FILES taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
++INSTALL( FILES rccpatch.h taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
+diff -dPNur taglib-1.5/taglib/toolkit/Makefile.am taglib-1.5-ds/taglib/toolkit/Makefile.am
+--- taglib-1.5/taglib/toolkit/Makefile.am 2008-01-11 01:54:01.000000000 +0100
++++ taglib-1.5-ds/taglib/toolkit/Makefile.am 2008-11-20 15:24:19.000000000 +0100
+@@ -1,14 +1,20 @@
+ INCLUDES = \
+ -I$(top_srcdir)/taglib \
+- $(all_includes)
++ $(all_includes) \
++ @LIBRCC_INCLUDES@
+
+ noinst_LTLIBRARIES = libtoolkit.la
+
++libtoolkit_la_LDFLAGS = @LIBRCC_LIBS@
++
+ libtoolkit_la_SOURCES = \
++ rccpatch.cpp \
+ tstring.cpp tstringlist.cpp tbytevector.cpp \
+ tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp
+
++
+ taglib_include_HEADERS = \
++ rccpatch.h \
+ taglib.h tstring.h tlist.h tlist.tcc tstringlist.h \
+ tbytevector.h tbytevectorlist.h tfile.h \
+ tmap.h tmap.tcc
+diff -dPNur taglib-1.5/taglib/toolkit/rccpatch.cpp taglib-1.5-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.5/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.5-ds/taglib/toolkit/rccpatch.cpp 2008-11-20 15:58:31.000000000 +0100
+@@ -0,0 +1,198 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.5/taglib/toolkit/rccpatch.h taglib-1.5-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.5/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.5-ds/taglib/toolkit/rccpatch.h 2008-11-20 15:24:19.000000000 +0100
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.5/taglib/toolkit/tstring.cpp taglib-1.5-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.5/taglib/toolkit/tstring.cpp 2008-02-04 16:14:45.000000000 +0100
++++ taglib-1.5-ds/taglib/toolkit/tstring.cpp 2008-11-20 15:24:21.000000000 +0100
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -167,7 +168,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -358,10 +359,21 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
+ case Latin1:
++ case Latin1ID3:
++ case Latin1ID3V2:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeOutputID3(s, true);
++ else /* if (t == Latin1(Locale) */ v = rccPatchRecodeOutput(s);
++
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -692,6 +704,31 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ }
++
++ t = UTF8;
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -781,6 +818,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.5/taglib/toolkit/tstring.h taglib-1.5-ds/taglib/toolkit/tstring.h
+--- taglib-1.5/taglib/toolkit/tstring.h 2008-02-04 16:14:45.000000000 +0100
++++ taglib-1.5-ds/taglib/toolkit/tstring.h 2008-11-20 15:24:21.000000000 +0100
+@@ -81,6 +81,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -103,6 +115,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.6-ds-rusxmms.patch b/patches/taglib/taglib-1.6-ds-rusxmms.patch
new file mode 100644
index 0000000..5eb1a2a
--- /dev/null
+++ b/patches/taglib/taglib-1.6-ds-rusxmms.patch
@@ -0,0 +1,587 @@
+diff -dPNur taglib-1.6/config-taglib.h.cmake taglib-1.6-ds/config-taglib.h.cmake
+--- taglib-1.6/config-taglib.h.cmake 2008-11-12 09:17:11.000000000 +0100
++++ taglib-1.6-ds/config-taglib.h.cmake 2009-10-02 17:53:08.000000000 +0200
+@@ -6,6 +6,8 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+ #cmakedefine WITH_ASF 1
+ #cmakedefine WITH_MP4 1
+diff -dPNur taglib-1.6/ConfigureChecks.cmake taglib-1.6-ds/ConfigureChecks.cmake
+--- taglib-1.6/ConfigureChecks.cmake 2008-12-21 22:46:41.000000000 +0100
++++ taglib-1.6-ds/ConfigureChecks.cmake 2009-10-02 17:53:08.000000000 +0200
+@@ -14,6 +14,8 @@
+ #check for libz using the cmake supplied FindZLIB.cmake
+ FIND_PACKAGE(ZLIB)
+
++SET(HAVE_LIBRCC 1)
++
+ IF(ZLIB_FOUND)
+ SET(HAVE_ZLIB 1)
+ ELSE(ZLIB_FOUND)
+diff -dPNur taglib-1.6/configure.in taglib-1.6-ds/configure.in
+--- taglib-1.6/configure.in 2009-09-13 13:58:46.000000000 +0200
++++ taglib-1.6-ds/configure.in 2009-10-02 17:53:08.000000000 +0200
+@@ -99,6 +99,20 @@
+
+ AC_SUBST(AUTODIRS)
+
++AC_CHECK_LIB(rcc, rccInit,[
++ AC_CHECK_HEADERS(librcc.h,[
++ LIBRCC_LIBS="-lrcc"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
++
+ #AM_INIT_AUTOMAKE(taglib,1.0)
+ dnl don't remove the below
+ dnl AC_OUTPUT(taglib-config)
+diff -dPNur taglib-1.6/configure.in.in taglib-1.6-ds/configure.in.in
+--- taglib-1.6/configure.in.in 2009-09-13 13:30:19.000000000 +0200
++++ taglib-1.6-ds/configure.in.in 2009-10-02 17:53:08.000000000 +0200
+@@ -95,6 +95,21 @@
+
+ AC_SUBST(AUTODIRS)
+
++AC_CHECK_LIB(rcc, rccInit,[
++ AC_CHECK_HEADERS(librcc.h,[
++ LIBRCC_LIBS="-lrcc"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
++
++
+ #AM_INIT_AUTOMAKE(taglib,1.0)
+ dnl don't remove the below
+ dnl AC_OUTPUT(taglib-config)
+diff -dPNur taglib-1.6/taglib/CMakeLists.txt taglib-1.6-ds/taglib/CMakeLists.txt
+--- taglib-1.6/taglib/CMakeLists.txt 2009-09-13 12:19:34.000000000 +0200
++++ taglib-1.6-ds/taglib/CMakeLists.txt 2009-10-02 17:53:08.000000000 +0200
+@@ -163,6 +163,7 @@
+ )
+
+ SET(toolkit_SRCS
++toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -190,7 +191,7 @@
+ add_library(tag SHARED ${tag_LIB_SRCS})
+ endif(ENABLE_STATIC)
+
+-TARGET_LINK_LIBRARIES(tag )
++TARGET_LINK_LIBRARIES(tag rcc)
+ if(ZLIB_FOUND)
+ TARGET_LINK_LIBRARIES(tag ${ZLIB_LIBRARIES})
+ endif(ZLIB_FOUND)
+diff -dPNur taglib-1.6/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.6-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.6/taglib/mpeg/id3v1/id3v1tag.cpp 2008-02-04 16:11:56.000000000 +0100
++++ taglib-1.6-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -59,17 +59,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -240,7 +241,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.6/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.6-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.6/taglib/mpeg/id3v2/frames/commentsframe.cpp 2008-02-04 16:11:56.000000000 +0100
++++ taglib-1.6-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -136,10 +136,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = d->textEncoding == (String::Latin1 || String::Latin1ID3 || String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -155,10 +155,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkEncoding(d->description, encoding);
+ encoding = checkEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.6/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.6-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.6/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2008-02-04 16:11:56.000000000 +0100
++++ taglib-1.6-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -105,12 +105,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -139,11 +139,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.6/taglib/toolkit/CMakeLists.txt taglib-1.6-ds/taglib/toolkit/CMakeLists.txt
+--- taglib-1.6/taglib/toolkit/CMakeLists.txt 2006-09-20 14:52:28.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/CMakeLists.txt 2009-10-02 17:53:08.000000000 +0200
+@@ -1 +1 @@
+-INSTALL( FILES taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
++INSTALL( FILES rccpatch.h taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
+diff -dPNur taglib-1.6/taglib/toolkit/Makefile.am taglib-1.6-ds/taglib/toolkit/Makefile.am
+--- taglib-1.6/taglib/toolkit/Makefile.am 2009-09-04 11:07:27.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/Makefile.am 2009-10-03 02:34:01.000000000 +0200
+@@ -1,15 +1,21 @@
+ DEFS = -DMAKE_TAGLIB_LIB @DEFS@
+ INCLUDES = \
+ -I$(top_srcdir)/taglib \
+- $(all_includes)
++ $(all_includes) \
++ @LIBRCC_INCLUDES@
++
++libtoolkit_la_LIBADD = @LIBRCC_LIBS@
+
+ noinst_LTLIBRARIES = libtoolkit.la
+
+ libtoolkit_la_SOURCES = \
++ rccpatch.cpp \
+ tstring.cpp tstringlist.cpp tbytevector.cpp \
+ tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp
+
++
+ taglib_include_HEADERS = \
++ rccpatch.h \
+ taglib.h tstring.h tlist.h tlist.tcc tstringlist.h \
+ tbytevector.h tbytevectorlist.h tfile.h \
+ tmap.h tmap.tcc
+diff -dPNur taglib-1.6/taglib/toolkit/rccpatch.cpp taglib-1.6-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.6/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.6-ds/taglib/toolkit/rccpatch.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -0,0 +1,198 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.6/taglib/toolkit/rccpatch.h taglib-1.6-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.6/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.6-ds/taglib/toolkit/rccpatch.h 2009-10-02 17:53:08.000000000 +0200
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.6/taglib/toolkit/tstring.cpp taglib-1.6-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.6/taglib/toolkit/tstring.cpp 2009-04-29 17:57:05.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/tstring.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -167,7 +168,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -369,10 +370,21 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
+ case Latin1:
++ case Latin1ID3:
++ case Latin1ID3V2:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeOutputID3(s, true);
++ else /* if (t == Latin1(Locale) */ v = rccPatchRecodeOutput(s);
++
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -707,6 +719,31 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ }
++
++ t = UTF8;
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -796,6 +833,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.6/taglib/toolkit/tstring.h taglib-1.6-ds/taglib/toolkit/tstring.h
+--- taglib-1.6/taglib/toolkit/tstring.h 2009-07-02 22:54:32.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/tstring.h 2009-10-02 17:53:08.000000000 +0200
+@@ -81,6 +81,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -103,6 +115,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.7-ds-rusxmms-r2.patch b/patches/taglib/taglib-1.7-ds-rusxmms-r2.patch
new file mode 100644
index 0000000..0757692
--- /dev/null
+++ b/patches/taglib/taglib-1.7-ds-rusxmms-r2.patch
@@ -0,0 +1,506 @@
+diff -dPNur taglib-1.7.2/config-taglib.h.cmake taglib-1.7.2-ds/config-taglib.h.cmake
+--- taglib-1.7.2/config-taglib.h.cmake 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/config-taglib.h.cmake 2013-01-29 12:30:59.000000000 +0100
+@@ -6,6 +6,8 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+ #cmakedefine WITH_ASF 1
+ #cmakedefine WITH_MP4 1
+diff -dPNur taglib-1.7.2/ConfigureChecks.cmake taglib-1.7.2-ds/ConfigureChecks.cmake
+--- taglib-1.7.2/ConfigureChecks.cmake 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/ConfigureChecks.cmake 2013-01-29 12:30:59.000000000 +0100
+@@ -14,6 +14,8 @@
+ #check for libz using the cmake supplied FindZLIB.cmake
+ FIND_PACKAGE(ZLIB)
+
++SET(HAVE_LIBRCC 1)
++
+ IF(ZLIB_FOUND)
+ SET(HAVE_ZLIB 1)
+ ELSE(ZLIB_FOUND)
+diff -dPNur taglib-1.7.2/taglib/CMakeLists.txt taglib-1.7.2-ds/taglib/CMakeLists.txt
+--- taglib-1.7.2/taglib/CMakeLists.txt 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/CMakeLists.txt 2013-01-29 12:30:59.000000000 +0100
+@@ -171,6 +171,7 @@
+ )
+
+ SET(toolkit_SRCS
++toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -198,7 +199,7 @@
+ add_library(tag SHARED ${tag_LIB_SRCS})
+ endif(ENABLE_STATIC)
+
+-TARGET_LINK_LIBRARIES(tag )
++TARGET_LINK_LIBRARIES(tag rcc)
+ if(ZLIB_FOUND)
+ TARGET_LINK_LIBRARIES(tag ${ZLIB_LIBRARIES})
+ endif(ZLIB_FOUND)
+diff -dPNur taglib-1.7.2/taglib/CMakeLists.txt.orig taglib-1.7.2-ds/taglib/CMakeLists.txt.orig
+diff -dPNur taglib-1.7.2/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.7.2-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.7.2/taglib/mpeg/id3v1/id3v1tag.cpp 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2013-01-29 12:30:59.000000000 +0100
+@@ -59,17 +59,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -240,7 +241,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.7.2/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.7.2-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.7.2/taglib/mpeg/id3v2/frames/commentsframe.cpp 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2013-01-29 12:30:59.000000000 +0100
+@@ -136,10 +136,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -155,10 +155,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkEncoding(d->description, encoding);
+ encoding = checkEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.7.2/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.7.2-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.7.2/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2013-01-29 12:30:59.000000000 +0100
+@@ -105,12 +105,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -139,11 +139,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.7.2/taglib/toolkit/CMakeLists.txt taglib-1.7.2-ds/taglib/toolkit/CMakeLists.txt
+--- taglib-1.7.2/taglib/toolkit/CMakeLists.txt 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/toolkit/CMakeLists.txt 2013-01-29 12:30:59.000000000 +0100
+@@ -1 +1 @@
+-INSTALL( FILES taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
++INSTALL( FILES rccpatch.h taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
+diff -dPNur taglib-1.7.2/taglib/toolkit/rccpatch.cpp taglib-1.7.2-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.7.2/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.7.2-ds/taglib/toolkit/rccpatch.cpp 2013-01-29 12:35:45.000000000 +0100
+@@ -0,0 +1,192 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.7.2/taglib/toolkit/rccpatch.h taglib-1.7.2-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.7.2/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.7.2-ds/taglib/toolkit/rccpatch.h 2013-01-29 12:30:59.000000000 +0100
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.7.2/taglib/toolkit/tstring.cpp taglib-1.7.2-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.7.2/taglib/toolkit/tstring.cpp 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/toolkit/tstring.cpp 2013-01-29 12:34:24.000000000 +0100
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -167,7 +168,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -369,10 +370,21 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
+ case Latin1:
++ case Latin1ID3:
++ case Latin1ID3V2:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeOutputID3(s, true);
++ else /* if (t == Latin1(Locale) */ v = rccPatchRecodeOutput(s);
++
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -717,6 +729,30 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ t = UTF8;
++ }
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -806,6 +842,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.7.2/taglib/toolkit/tstring.h taglib-1.7.2-ds/taglib/toolkit/tstring.h
+--- taglib-1.7.2/taglib/toolkit/tstring.h 2012-04-20 17:57:13.000000000 +0200
++++ taglib-1.7.2-ds/taglib/toolkit/tstring.h 2013-01-29 12:30:59.000000000 +0100
+@@ -88,6 +88,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -110,6 +122,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.7-ds-rusxmms.patch b/patches/taglib/taglib-1.7-ds-rusxmms.patch
new file mode 100644
index 0000000..fce777f
--- /dev/null
+++ b/patches/taglib/taglib-1.7-ds-rusxmms.patch
@@ -0,0 +1,515 @@
+diff -dPNur taglib-1.6/config-taglib.h.cmake taglib-1.6-ds/config-taglib.h.cmake
+--- taglib-1.6/config-taglib.h.cmake 2008-11-12 09:17:11.000000000 +0100
++++ taglib-1.6-ds/config-taglib.h.cmake 2009-10-02 17:53:08.000000000 +0200
+@@ -6,6 +6,8 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+ #cmakedefine WITH_ASF 1
+ #cmakedefine WITH_MP4 1
+diff -dPNur taglib-1.6/ConfigureChecks.cmake taglib-1.6-ds/ConfigureChecks.cmake
+--- taglib-1.6/ConfigureChecks.cmake 2008-12-21 22:46:41.000000000 +0100
++++ taglib-1.6-ds/ConfigureChecks.cmake 2009-10-02 17:53:08.000000000 +0200
+@@ -14,6 +14,8 @@
+ #check for libz using the cmake supplied FindZLIB.cmake
+ FIND_PACKAGE(ZLIB)
+
++SET(HAVE_LIBRCC 1)
++
+ IF(ZLIB_FOUND)
+ SET(HAVE_ZLIB 1)
+ ELSE(ZLIB_FOUND)
+diff -dPNur taglib-1.6/configure.in taglib-1.6-ds/configure.in
+diff -dPNur taglib-1.6/configure.in.in taglib-1.6-ds/configure.in.in
+diff -dPNur taglib-1.6/taglib/CMakeLists.txt taglib-1.6-ds/taglib/CMakeLists.txt
+--- taglib-1.6/taglib/CMakeLists.txt 2009-09-13 12:19:34.000000000 +0200
++++ taglib-1.6-ds/taglib/CMakeLists.txt 2009-10-02 17:53:08.000000000 +0200
+@@ -163,6 +163,7 @@
+ )
+
+ SET(toolkit_SRCS
++toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -190,7 +191,7 @@
+ add_library(tag SHARED ${tag_LIB_SRCS})
+ endif(ENABLE_STATIC)
+
+-TARGET_LINK_LIBRARIES(tag )
++TARGET_LINK_LIBRARIES(tag rcc)
+ if(ZLIB_FOUND)
+ TARGET_LINK_LIBRARIES(tag ${ZLIB_LIBRARIES})
+ endif(ZLIB_FOUND)
+diff -dPNur taglib-1.6/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.6-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.6/taglib/mpeg/id3v1/id3v1tag.cpp 2008-02-04 16:11:56.000000000 +0100
++++ taglib-1.6-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -59,17 +59,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -240,7 +241,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.6/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.6-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.6/taglib/mpeg/id3v2/frames/commentsframe.cpp 2008-02-04 16:11:56.000000000 +0100
++++ taglib-1.6-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -136,10 +136,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -155,10 +155,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkEncoding(d->description, encoding);
+ encoding = checkEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.6/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.6-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.6/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2008-02-04 16:11:56.000000000 +0100
++++ taglib-1.6-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -105,12 +105,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -139,11 +139,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.6/taglib/toolkit/CMakeLists.txt taglib-1.6-ds/taglib/toolkit/CMakeLists.txt
+--- taglib-1.6/taglib/toolkit/CMakeLists.txt 2006-09-20 14:52:28.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/CMakeLists.txt 2009-10-02 17:53:08.000000000 +0200
+@@ -1 +1 @@
+-INSTALL( FILES taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
++INSTALL( FILES rccpatch.h taglib.h tstring.h tlist.h tlist.tcc tstringlist.h tbytevector.h tbytevectorlist.h tfile.h tmap.h tmap.tcc DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
+diff -dPNur taglib-1.6/taglib/toolkit/Makefile.am taglib-1.6-ds/taglib/toolkit/Makefile.am
+diff -dPNur taglib-1.6/taglib/toolkit/rccpatch.cpp taglib-1.6-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.6/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.6-ds/taglib/toolkit/rccpatch.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -0,0 +1,198 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.6/taglib/toolkit/rccpatch.h taglib-1.6-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.6/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.6-ds/taglib/toolkit/rccpatch.h 2009-10-02 17:53:08.000000000 +0200
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.6/taglib/toolkit/tstring.cpp taglib-1.6-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.6/taglib/toolkit/tstring.cpp 2009-04-29 17:57:05.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/tstring.cpp 2009-10-02 17:53:08.000000000 +0200
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -167,7 +168,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -369,10 +370,21 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
+ case Latin1:
++ case Latin1ID3:
++ case Latin1ID3V2:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeOutputID3(s, true);
++ else /* if (t == Latin1(Locale) */ v = rccPatchRecodeOutput(s);
++
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -707,6 +719,31 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ }
++
++ t = UTF8;
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -796,6 +833,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.6/taglib/toolkit/tstring.h taglib-1.6-ds/taglib/toolkit/tstring.h
+--- taglib-1.6/taglib/toolkit/tstring.h 2009-07-02 22:54:32.000000000 +0200
++++ taglib-1.6-ds/taglib/toolkit/tstring.h 2009-10-02 17:53:08.000000000 +0200
+@@ -81,6 +81,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -103,6 +115,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.8-ds-rusxmms-r2.patch b/patches/taglib/taglib-1.8-ds-rusxmms-r2.patch
new file mode 100644
index 0000000..bed92a2
--- /dev/null
+++ b/patches/taglib/taglib-1.8-ds-rusxmms-r2.patch
@@ -0,0 +1,507 @@
+diff -dPNur taglib-1.8/config-taglib.h.cmake taglib-1.8-ds/config-taglib.h.cmake
+--- taglib-1.8/config-taglib.h.cmake 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/config-taglib.h.cmake 2013-01-29 12:45:48.000000000 +0100
+@@ -3,6 +3,8 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+ #cmakedefine WITH_ASF 1
+ #cmakedefine WITH_MP4 1
+diff -dPNur taglib-1.8/ConfigureChecks.cmake taglib-1.8-ds/ConfigureChecks.cmake
+--- taglib-1.8/ConfigureChecks.cmake 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/ConfigureChecks.cmake 2013-01-29 12:45:48.000000000 +0100
+@@ -14,6 +14,8 @@
+ set(HAVE_ZLIB 0)
+ endif()
+
++SET(HAVE_LIBRCC 1)
++
+ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
+ find_package(CppUnit)
+ if(NOT CppUnit_FOUND AND BUILD_TESTS)
+diff -dPNur taglib-1.8/taglib/CMakeLists.txt taglib-1.8-ds/taglib/CMakeLists.txt
+--- taglib-1.8/taglib/CMakeLists.txt 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/CMakeLists.txt 2013-01-29 12:45:48.000000000 +0100
+@@ -35,6 +35,7 @@
+ audioproperties.h
+ taglib_export.h
+ ${CMAKE_BINARY_DIR}/taglib_config.h
++ toolkit/rccpatch.h
+ toolkit/taglib.h
+ toolkit/tstring.h
+ toolkit/tlist.h
+@@ -269,6 +270,7 @@
+ )
+
+ set(toolkit_SRCS
++ toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -296,7 +298,7 @@
+ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
+
+ if(ZLIB_FOUND)
+- target_link_libraries(tag ${ZLIB_LIBRARIES})
++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
+ endif()
+
+ set_target_properties(tag PROPERTIES
+diff -dPNur taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2013-01-29 12:45:48.000000000 +0100
+@@ -64,17 +64,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -247,7 +248,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2013-01-29 12:45:48.000000000 +0100
+@@ -150,10 +150,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -174,10 +174,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkTextEncoding(d->description, encoding);
+ encoding = checkTextEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2013-01-29 12:45:48.000000000 +0100
+@@ -187,12 +187,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -223,11 +223,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkTextEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.8/taglib/toolkit/rccpatch.cpp taglib-1.8-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.8/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.8-ds/taglib/toolkit/rccpatch.cpp 2013-01-29 12:35:45.000000000 +0100
+@@ -0,0 +1,192 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.8/taglib/toolkit/rccpatch.h taglib-1.8-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.8/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.8-ds/taglib/toolkit/rccpatch.h 2013-01-29 12:45:48.000000000 +0100
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.cpp taglib-1.8-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.8/taglib/toolkit/tstring.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/toolkit/tstring.cpp 2013-01-29 12:46:14.000000000 +0100
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -168,7 +169,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -397,10 +398,21 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
+ case Latin1:
++ case Latin1ID3:
++ case Latin1ID3V2:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeOutputID3(s, true);
++ else /* if (t == Latin1(Locale) */ v = rccPatchRecodeOutput(s);
++
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -750,6 +762,30 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ t = UTF8;
++ }
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -839,6 +875,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.h taglib-1.8-ds/taglib/toolkit/tstring.h
+--- taglib-1.8/taglib/toolkit/tstring.h 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/toolkit/tstring.h 2013-01-29 12:45:48.000000000 +0100
+@@ -90,6 +90,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -112,6 +124,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.8-ds-rusxmms-r9.patch b/patches/taglib/taglib-1.8-ds-rusxmms-r9.patch
new file mode 100644
index 0000000..28a7b84
--- /dev/null
+++ b/patches/taglib/taglib-1.8-ds-rusxmms-r9.patch
@@ -0,0 +1,609 @@
+diff -dPNur taglib-1.8/config-taglib.h.cmake taglib-1.8-ds/config-taglib.h.cmake
+--- taglib-1.8/config-taglib.h.cmake 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/config-taglib.h.cmake 2013-05-22 20:13:15.000000000 +0200
+@@ -3,6 +3,8 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+ #cmakedefine WITH_ASF 1
+ #cmakedefine WITH_MP4 1
+diff -dPNur taglib-1.8/ConfigureChecks.cmake taglib-1.8-ds/ConfigureChecks.cmake
+--- taglib-1.8/ConfigureChecks.cmake 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/ConfigureChecks.cmake 2013-05-22 20:13:15.000000000 +0200
+@@ -14,6 +14,8 @@
+ set(HAVE_ZLIB 0)
+ endif()
+
++SET(HAVE_LIBRCC 1)
++
+ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
+ find_package(CppUnit)
+ if(NOT CppUnit_FOUND AND BUILD_TESTS)
+diff -dPNur taglib-1.8/examples/tagreader_c.c taglib-1.8-ds/examples/tagreader_c.c
+--- taglib-1.8/examples/tagreader_c.c 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/examples/tagreader_c.c 2013-05-22 20:13:15.000000000 +0200
+@@ -38,7 +38,7 @@
+ TagLib_Tag *tag;
+ const TagLib_AudioProperties *properties;
+
+- taglib_set_strings_unicode(FALSE);
++// taglib_set_strings_unicode(FALSE);
+
+ for(i = 1; i < argc; i++) {
+ printf("******************** \"%s\" ********************\n", argv[i]);
+diff -dPNur taglib-1.8/examples/tagwriter.cpp taglib-1.8-ds/examples/tagwriter.cpp
+--- taglib-1.8/examples/tagwriter.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/examples/tagwriter.cpp 2013-05-22 20:13:15.000000000 +0200
+@@ -92,7 +92,7 @@
+ if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
+
+ char field = argv[i][1];
+- TagLib::String value = argv[i + 1];
++ TagLib::String value(argv[i + 1], TagLib::String::Locale);
+
+ TagLib::List<TagLib::FileRef>::Iterator it;
+ for(it = fileList.begin(); it != fileList.end(); ++it) {
+diff -dPNur taglib-1.8/taglib/CMakeLists.txt taglib-1.8-ds/taglib/CMakeLists.txt
+--- taglib-1.8/taglib/CMakeLists.txt 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/CMakeLists.txt 2013-05-22 20:13:15.000000000 +0200
+@@ -35,6 +35,7 @@
+ audioproperties.h
+ taglib_export.h
+ ${CMAKE_BINARY_DIR}/taglib_config.h
++ toolkit/rccpatch.h
+ toolkit/taglib.h
+ toolkit/tstring.h
+ toolkit/tlist.h
+@@ -269,6 +270,7 @@
+ )
+
+ set(toolkit_SRCS
++ toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -296,7 +298,7 @@
+ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
+
+ if(ZLIB_FOUND)
+- target_link_libraries(tag ${ZLIB_LIBRARIES})
++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
+ endif()
+
+ set_target_properties(tag PROPERTIES
+diff -dPNur taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2013-05-22 20:13:15.000000000 +0200
+@@ -64,17 +64,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -247,7 +248,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2013-05-22 20:13:16.000000000 +0200
+@@ -150,10 +150,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -174,10 +174,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkTextEncoding(d->description, encoding);
+ encoding = checkTextEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2013-05-22 20:13:16.000000000 +0200
+@@ -187,12 +187,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -223,11 +223,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkTextEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/id3v2frame.cpp taglib-1.8-ds/taglib/mpeg/id3v2/id3v2frame.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/id3v2frame.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/id3v2frame.cpp 2013-05-22 20:10:07.000000000 +0200
+@@ -295,7 +295,7 @@
+ if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4)
+ return String::UTF16;
+
+- if(encoding != String::Latin1)
++ if((encoding != String::Latin1)&&(encoding != String::Latin1ID3V2))
+ return encoding;
+
+ for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
+diff -dPNur taglib-1.8/taglib/toolkit/rccpatch.cpp taglib-1.8-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.8/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.8-ds/taglib/toolkit/rccpatch.cpp 2013-05-22 20:13:16.000000000 +0200
+@@ -0,0 +1,237 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++//#define RCC_DEBUG
++
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# ifdef RCC_DEBUG
++# include <stdio.h>
++# endif /* RCC_DEBUG */
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccTaglibPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccTaglibPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccTaglibPatchInit();
++ if (rcc_initialized) atexit(rccTaglibPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Output: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" OutputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Input: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" InputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::String::Type rccTaglibPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccTaglibPatchTryInit();
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccTaglibPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccTaglibPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ } else {
++ // Error or no-language configured: If Latin1ID3V2 is returned we normally will use the default unicode encoding unless Latin1 is selected by taglib
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.8/taglib/toolkit/rccpatch.h taglib-1.8-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.8/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.8-ds/taglib/toolkit/rccpatch.h 2013-05-22 20:13:16.000000000 +0200
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccTaglibPatchFree();
++void rccTaglibPatchInit();
++void rccTaglibPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccTaglibPatchGetLocaleType();
++TagLib::String::Type rccTaglibPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.cpp taglib-1.8-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.8/taglib/toolkit/tstring.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/toolkit/tstring.cpp 2013-05-22 20:13:16.000000000 +0200
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -168,7 +169,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -397,10 +398,38 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) {
++ // The source is either Unicode or real Latin1 (if rcc is bypassed)
++ std::string s = to8Bit(true);
++
++ // In case of UTF8 locale, this probably will return NULL (no recoding needed), but we will take UTF8 path in the next swtich
++ v = rccTaglibPatchRecodeOutput(s);
++ if (v.size()) return v;
+
++ t = rccTaglibPatchGetLocaleType();
++ }
++
++ switch(t) {
++ case Latin1ID3:
++ case Latin1ID3V2:
++ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeOutputID3(s, true);
++ if (v.size()) break;
++
++ // we don't know if we got NULL because rcc is disabled (error) or UTF8 output is required
++ if ((t == Latin1ID3V2)&&(rccTaglibPatchGetID3Type() == UTF8)) {
++ v.setData(s.c_str(), s.length());
++ } else {
++ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
++ v.append(char(*it));
++ }
++ break;
++ }
+ case Latin1:
+ {
++ // We can have the UTF16 inside, but first 256 positions is equal to Latin1
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -750,6 +779,34 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccTaglibPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccTaglibPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ t = UTF8;
++ } else {
++ // We don't know if we got UTF-8 encoded string or either rcc is disable or something is failed,
++ // since standard applications are really expecting here Latin1, it is safe to just check if we have violations of UTF8
++ //if (Unicode::isLegalUTF8(s)) t = UTF8;
++ }
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -839,6 +896,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccTaglibPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)||(rcc_type == Latin1)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.h taglib-1.8-ds/taglib/toolkit/tstring.h
+--- taglib-1.8/taglib/toolkit/tstring.h 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/toolkit/tstring.h 2013-05-22 20:13:16.000000000 +0200
+@@ -90,6 +90,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -112,6 +124,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
diff --git a/patches/taglib/taglib-1.8-ds-rusxmms.patch b/patches/taglib/taglib-1.8-ds-rusxmms.patch
new file mode 100644
index 0000000..a5c04a5
--- /dev/null
+++ b/patches/taglib/taglib-1.8-ds-rusxmms.patch
@@ -0,0 +1,519 @@
+diff -dPNur taglib-1.8/config-taglib.h.cmake taglib-1.8-ds/config-taglib.h.cmake
+--- taglib-1.8/config-taglib.h.cmake 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/config-taglib.h.cmake 2012-11-11 09:59:50.000000000 +0100
+@@ -3,6 +3,8 @@
+ /* Define if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++#cmakedefine HAVE_LIBRCC 1
++
+ #cmakedefine NO_ITUNES_HACKS 1
+ #cmakedefine WITH_ASF 1
+ #cmakedefine WITH_MP4 1
+diff -dPNur taglib-1.8/ConfigureChecks.cmake taglib-1.8-ds/ConfigureChecks.cmake
+--- taglib-1.8/ConfigureChecks.cmake 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/ConfigureChecks.cmake 2012-11-11 10:01:48.000000000 +0100
+@@ -14,6 +14,8 @@
+ set(HAVE_ZLIB 0)
+ endif()
+
++SET(HAVE_LIBRCC 1)
++
+ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
+ find_package(CppUnit)
+ if(NOT CppUnit_FOUND AND BUILD_TESTS)
+diff -dPNur taglib-1.8/taglib/CMakeLists.txt taglib-1.8-ds/taglib/CMakeLists.txt
+--- taglib-1.8/taglib/CMakeLists.txt 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/CMakeLists.txt 2012-11-11 10:04:40.000000000 +0100
+@@ -35,6 +35,7 @@
+ audioproperties.h
+ taglib_export.h
+ ${CMAKE_BINARY_DIR}/taglib_config.h
++ toolkit/rccpatch.h
+ toolkit/taglib.h
+ toolkit/tstring.h
+ toolkit/tlist.h
+@@ -269,6 +270,7 @@
+ )
+
+ set(toolkit_SRCS
++ toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -296,7 +298,7 @@
+ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
+
+ if(ZLIB_FOUND)
+- target_link_libraries(tag ${ZLIB_LIBRARIES})
++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
+ endif()
+
+ set_target_properties(tag PROPERTIES
+diff -dPNur taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2012-11-11 09:59:50.000000000 +0100
+@@ -64,17 +64,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -247,7 +248,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.8/taglib/mpeg/id3v1/id3v1tag.cpp.orig taglib-1.8-ds/taglib/mpeg/id3v1/id3v1tag.cpp.orig
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2012-11-11 09:59:50.000000000 +0100
+@@ -150,10 +150,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -174,10 +174,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkTextEncoding(d->description, encoding);
+ encoding = checkTextEncoding(d->text, encoding);
+-
+- v.append(char(encoding));
++
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/commentsframe.cpp.orig taglib-1.8-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp.orig
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2012-11-11 09:59:50.000000000 +0100
+@@ -187,12 +187,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -223,11 +223,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkTextEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.8/taglib/mpeg/id3v2/frames/textidentificationframe.cpp.orig taglib-1.8-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp.orig
+diff -dPNur taglib-1.8/taglib/toolkit/rccpatch.cpp taglib-1.8-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.8/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.8-ds/taglib/toolkit/rccpatch.cpp 2012-11-11 10:00:09.000000000 +0100
+@@ -0,0 +1,198 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++ if (res) v.setData(res, rlen);
++ else v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::String::Type rccPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccPatchTryInit();
++
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.8/taglib/toolkit/rccpatch.h taglib-1.8-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.8/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.8-ds/taglib/toolkit/rccpatch.h 2012-11-11 10:00:09.000000000 +0100
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccPatchGetLocaleType();
++TagLib::String::Type rccPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.cpp taglib-1.8-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.8/taglib/toolkit/tstring.cpp 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/toolkit/tstring.cpp 2012-11-11 10:00:09.000000000 +0100
+@@ -23,6 +23,7 @@
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "unicode.h"
+ #include "tdebug.h"
+@@ -168,7 +169,7 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1 || t == UTF8) {
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2 || t == UTF8) {
+
+ int length = 0;
+ d->data.resize(v.size());
+@@ -397,10 +398,21 @@
+ {
+ ByteVector v;
+
+- switch(t) {
++ if (t == Locale) t = rccPatchGetLocaleType();
+
++ switch(t) {
++ case Locale:
+ case Latin1:
++ case Latin1ID3:
++ case Latin1ID3V2:
+ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeOutputID3(s, true);
++ else /* if (t == Latin1(Locale) */ v = rccPatchRecodeOutput(s);
++
++ if (v.size()) return v;
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ v.append(char(*it));
+ break;
+@@ -750,6 +762,31 @@
+
+ void String::prepare(Type t)
+ {
++ if (t == Locale) t = rccPatchGetLocaleType();
++
++ if ((t == Latin1)||(t == Latin1ID3)||(t == Latin1ID3V2)) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccPatchRecodeInput(s);
++
++ if (v.size()) {
++ int length = 0;
++ d->data.resize(v.size());
++ wstring::iterator targetIt = d->data.begin();
++ for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
++ *targetIt = uchar(*it);
++ ++targetIt;
++ ++length;
++ }
++ d->data.resize(length);
++ }
++
++ t = UTF8;
++ }
++
+ switch(t) {
+ case UTF16:
+ {
+@@ -839,6 +876,27 @@
+
+ std::ostream &operator<<(std::ostream &s, const String &str)
+ {
+- s << str.to8Bit();
++ ByteVector bv = str.data(String::Locale);
++ s << bv;
+ return s;
+ }
++
++String::Type String::ID3Type(int i) {
++ if (i == Latin1) return Latin1ID3V2;
++ return Type(i);
++};
++
++String::Type String::ID3WType(Type type) {
++ Type rcc_type = rccPatchGetID3Type();
++ if ((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)) {
++ if (type == Latin1) return rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++String::Type String::ID3RealType(Type type) {
++ if ((type == Latin1ID3)||(type == Latin1ID3V2)) return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.cpp.orig taglib-1.8-ds/taglib/toolkit/tstring.cpp.orig
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.h taglib-1.8-ds/taglib/toolkit/tstring.h
+--- taglib-1.8/taglib/toolkit/tstring.h 2012-09-06 20:03:15.000000000 +0200
++++ taglib-1.8-ds/taglib/toolkit/tstring.h 2012-11-11 10:00:09.000000000 +0100
+@@ -90,6 +90,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -112,6 +124,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
+diff -dPNur taglib-1.8/taglib/toolkit/tstring.h.orig taglib-1.8-ds/taglib/toolkit/tstring.h.orig
diff --git a/patches/taglib/taglib-1.9.1-ds-rusxmms-enforce.patch b/patches/taglib/taglib-1.9.1-ds-rusxmms-enforce.patch
new file mode 100644
index 0000000..e980b7a
--- /dev/null
+++ b/patches/taglib/taglib-1.9.1-ds-rusxmms-enforce.patch
@@ -0,0 +1,20 @@
+--- taglib-1.9.1/taglib/mpeg/id3v1/id3v1tag.h 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-taurus/taglib/mpeg/id3v1/id3v1tag.h 2013-11-12 00:24:31.206495291 +0100
+@@ -68,7 +68,7 @@
+ * Decode a string from \a data. The default implementation assumes that
+ * \a data is an ISO-8859-1 (Latin1) character array.
+ */
+- virtual String parse(const ByteVector &data) const;
++ String parse(const ByteVector &data) const;
+
+ /*!
+ * Encode a ByteVector with the data from \a s. The default implementation
+@@ -79,7 +79,7 @@
+ * instead do not write an ID3v1 tag in the case that the data is not
+ * ISO-8859-1.
+ */
+- virtual ByteVector render(const String &s) const;
++ ByteVector render(const String &s) const;
+ };
+
+ //! The main class in the ID3v1 implementation
diff --git a/patches/taglib/taglib-1.9.1-ds-rusxmms.patch b/patches/taglib/taglib-1.9.1-ds-rusxmms.patch
new file mode 100644
index 0000000..b64b5b5
--- /dev/null
+++ b/patches/taglib/taglib-1.9.1-ds-rusxmms.patch
@@ -0,0 +1,676 @@
+diff -dPNur taglib-1.9.1/config.h.cmake taglib-1.9.1-ds/config.h.cmake
+--- taglib-1.9.1/config.h.cmake 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/config.h.cmake 2013-11-11 13:43:48.500304915 +0100
+@@ -31,6 +31,9 @@
+ /* Defined if you have libz */
+ #cmakedefine HAVE_ZLIB 1
+
++/* Defined if you have LibRCC from RusXMMS project */
++#cmakedefine HAVE_LIBRCC 1
++
+ /* Indicates whether debug messages are shown even in release mode */
+ #cmakedefine TRACE_IN_RELEASE 1
+
+diff -dPNur taglib-1.9.1/ConfigureChecks.cmake taglib-1.9.1-ds/ConfigureChecks.cmake
+--- taglib-1.9.1/ConfigureChecks.cmake 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/ConfigureChecks.cmake 2013-11-11 13:42:53.017126134 +0100
+@@ -216,6 +216,7 @@
+ set(HAVE_ZLIB 0)
+ endif()
+
++SET(HAVE_LIBRCC 1)
+
+ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
+
+diff -dPNur taglib-1.9.1/examples/tagreader_c.c taglib-1.9.1-ds/examples/tagreader_c.c
+--- taglib-1.9.1/examples/tagreader_c.c 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/examples/tagreader_c.c 2013-11-11 13:42:53.017126134 +0100
+@@ -38,7 +38,7 @@
+ TagLib_Tag *tag;
+ const TagLib_AudioProperties *properties;
+
+- taglib_set_strings_unicode(FALSE);
++// taglib_set_strings_unicode(FALSE);
+
+ for(i = 1; i < argc; i++) {
+ printf("******************** \"%s\" ********************\n", argv[i]);
+diff -dPNur taglib-1.9.1/examples/tagwriter.cpp taglib-1.9.1-ds/examples/tagwriter.cpp
+--- taglib-1.9.1/examples/tagwriter.cpp 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/examples/tagwriter.cpp 2013-11-11 13:42:53.028126368 +0100
+@@ -92,7 +92,7 @@
+ if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
+
+ char field = argv[i][1];
+- TagLib::String value = argv[i + 1];
++ TagLib::String value(argv[i + 1], TagLib::String::Locale);
+
+ TagLib::List<TagLib::FileRef>::Iterator it;
+ for(it = fileList.begin(); it != fileList.end(); ++it) {
+diff -dPNur taglib-1.9.1/taglib/CMakeLists.txt taglib-1.9.1-ds/taglib/CMakeLists.txt
+--- taglib-1.9.1/taglib/CMakeLists.txt 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/CMakeLists.txt 2013-11-11 13:42:53.042126665 +0100
+@@ -36,6 +36,7 @@
+ audioproperties.h
+ taglib_export.h
+ ${CMAKE_BINARY_DIR}/taglib_config.h
++ toolkit/rccpatch.h
+ toolkit/taglib.h
+ toolkit/tstring.h
+ toolkit/tlist.h
+@@ -281,6 +282,7 @@
+ )
+
+ set(toolkit_SRCS
++ toolkit/rccpatch.cpp
+ toolkit/tstring.cpp
+ toolkit/tstringlist.cpp
+ toolkit/tbytevector.cpp
+@@ -310,7 +312,7 @@
+ add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
+
+ if(ZLIB_FOUND)
+- target_link_libraries(tag ${ZLIB_LIBRARIES})
++ target_link_libraries(tag rcc ${ZLIB_LIBRARIES})
+ endif()
+
+ set_target_properties(tag PROPERTIES
+diff -dPNur taglib-1.9.1/taglib/mpeg/id3v1/id3v1tag.cpp taglib-1.9.1-ds/taglib/mpeg/id3v1/id3v1tag.cpp
+--- taglib-1.9.1/taglib/mpeg/id3v1/id3v1tag.cpp 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/mpeg/id3v1/id3v1tag.cpp 2013-11-11 13:42:53.043126686 +0100
+@@ -64,17 +64,18 @@
+
+ String ID3v1::StringHandler::parse(const ByteVector &data) const
+ {
+- return String(data, String::Latin1).stripWhiteSpace();
++ return String(data, String::Latin1ID3).stripWhiteSpace();
+ }
+
+ ByteVector ID3v1::StringHandler::render(const String &s) const
+ {
+ if(!s.isLatin1())
+ {
++ if (String::ID3WType(String::Latin1) == String::Latin1)
+ return ByteVector();
+ }
+
+- return s.data(String::Latin1);
++ return s.data(String::Latin1ID3);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -257,7 +258,7 @@
+ d->track = uchar(data[offset + 29]);
+ }
+ else
+- d->comment = data.mid(offset, 30);
++ d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+
+ offset += 30;
+
+diff -dPNur taglib-1.9.1/taglib/mpeg/id3v2/frames/commentsframe.cpp taglib-1.9.1-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp
+--- taglib-1.9.1/taglib/mpeg/id3v2/frames/commentsframe.cpp 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/mpeg/id3v2/frames/commentsframe.cpp 2013-11-11 13:42:53.043126686 +0100
+@@ -150,10 +150,10 @@
+ return;
+ }
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+ d->language = data.mid(1, 3);
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
+
+@@ -174,10 +174,12 @@
+
+ String::Type encoding = d->textEncoding;
+
++ encoding = String::ID3WType(encoding);
++
+ encoding = checkTextEncoding(d->description, encoding);
+ encoding = checkTextEncoding(d->text, encoding);
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+ v.append(d->language.size() == 3 ? d->language : "XXX");
+ v.append(d->description.data(encoding));
+ v.append(textDelimiter(encoding));
+diff -dPNur taglib-1.9.1/taglib/mpeg/id3v2/frames/textidentificationframe.cpp taglib-1.9.1-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
+--- taglib-1.9.1/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/mpeg/id3v2/frames/textidentificationframe.cpp 2013-11-11 13:42:53.044126708 +0100
+@@ -187,12 +187,12 @@
+
+ // read the string data type (the first byte of the field data)
+
+- d->textEncoding = String::Type(data[0]);
++ d->textEncoding = String::ID3Type(data[0]);
+
+ // split the byte array into chunks based on the string type (two byte delimiter
+ // for unicode encodings)
+
+- int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
++ int byteAlign = (d->textEncoding == String::Latin1 || d->textEncoding == String::Latin1ID3 || d->textEncoding == String::Latin1ID3V2 || d->textEncoding == String::UTF8) ? 1 : 2;
+
+ // build a small counter to strip nulls off the end of the field
+
+@@ -223,11 +223,14 @@
+
+ ByteVector TextIdentificationFrame::renderFields() const
+ {
+- String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
++ String::Type encoding = d->textEncoding;
++
++ encoding = String::ID3WType(encoding);
++ encoding = checkTextEncoding(d->fieldList, encoding);
+
+ ByteVector v;
+
+- v.append(char(encoding));
++ v.append(char(String::ID3RealType(encoding)));
+
+ for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
+
+diff -dPNur taglib-1.9.1/taglib/mpeg/id3v2/id3v2frame.cpp taglib-1.9.1-ds/taglib/mpeg/id3v2/id3v2frame.cpp
+--- taglib-1.9.1/taglib/mpeg/id3v2/id3v2frame.cpp 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/mpeg/id3v2/id3v2frame.cpp 2013-11-11 13:42:53.045126729 +0100
+@@ -302,7 +302,7 @@
+ if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4)
+ return String::UTF16;
+
+- if(encoding != String::Latin1)
++ if((encoding != String::Latin1)&&(encoding != String::Latin1ID3V2))
+ return encoding;
+
+ for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
+diff -dPNur taglib-1.9.1/taglib/toolkit/rccpatch.cpp taglib-1.9.1-ds/taglib/toolkit/rccpatch.cpp
+--- taglib-1.9.1/taglib/toolkit/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.9.1-ds/taglib/toolkit/rccpatch.cpp 2013-11-11 13:42:53.045126729 +0100
+@@ -0,0 +1,237 @@
++#include <stdlib.h>
++
++#include <string>
++#include "tstring.h"
++#include "tbytevector.h"
++
++//#define RCC_DEBUG
++
++
++#ifndef HAVE_LIBRCC
++# include <config.h>
++#endif
++
++#ifdef HAVE_LIBRCC
++# ifdef RCC_DEBUG
++# include <stdio.h>
++# endif /* RCC_DEBUG */
++# include <librcc.h>
++# include <string.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define ID3V2_CLASS 1
++# define UTF_CLASS 2
++# define OUT_CLASS 3
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0},
++ { "out", RCC_CLASS_TRANSLATE_LOCALE, "LC_CTYPE", NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++
++static rcc_context ctx = NULL;
++#endif /* HAVE_LIBRCC */
++
++
++void rccTaglibPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++void rccTaglibPatchSetContext(void *newctx) {
++#ifdef HAVE_LIBRCC
++ if (newctx) {
++ ctx = (rcc_context)newctx;
++ rcc_initialized = 1;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rccTaglibPatchTryInit() {
++#ifdef HAVE_LIBRCC
++ if (!rcc_initialized) {
++ rccTaglibPatchInit();
++ if (rcc_initialized) atexit(rccTaglibPatchFree);
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, OUT_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Output: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, UTF_CLASS, v2?ID3V2_CLASS:ID3_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" OutputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else v.setData("", 0);
++ //v.setData(s.c_str(), s.length());
++
++ return v;
++#else
++ v.setData("", 0);
++
++ return v;
++#endif /* HAVE_LIBRCC */
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, OUT_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" Input: %s - %s\n", s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++
++ if (res) v.setData(res, rlen);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false) {
++ TagLib::ByteVector v;
++#ifdef HAVE_LIBRCC
++ size_t rlen;
++ char *res;
++
++ rccTaglibPatchTryInit();
++
++ res = rccSizedRecode(ctx, v2?ID3V2_CLASS:ID3_CLASS, UTF_CLASS, s.c_str(), s.length(), &rlen);
++#ifdef RCC_DEBUG
++ for (const unsigned char *c = (const unsigned char*)s.c_str(); *c; c++) {
++ if (*c > 127) {
++ printf(" InputID3(%i): %s - %s\n", v2, s.c_str(), res?res:"null");
++ break;
++ }
++ }
++#endif /* RCC_DEBUG */
++ if (res) v.setData(res, rlen + 1);
++ else
++#endif /* HAVE_LIBRCC */
++ v.setData("", 0);
++
++ return v;
++}
++
++TagLib::String::Type rccTaglibPatchGetLocaleType() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ char charset[32];
++
++ rccTaglibPatchTryInit();
++ if (!rccLocaleGetCharset(charset, NULL, 31)) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::UTF8;
++}
++
++TagLib::String::Type rccTaglibPatchGetID3Type() {
++#ifdef HAVE_LIBRCC
++ size_t len;
++ const char *charset;
++
++ rccTaglibPatchTryInit();
++
++ charset = rccGetCurrentCharsetName(ctx, ID3V2_CLASS);
++ if (charset) {
++ if (!strncmp(charset, "UTF", 3)) {
++ len = strlen(charset);
++
++ if (charset[len-1]=='8') return TagLib::String::UTF8;
++ if (!strcmp(charset+(len-2),"16")) return TagLib::String::UTF16;
++ if (!strcmp(charset+(len-4),"16LE")) return TagLib::String::UTF16LE;
++ if (!strcmp(charset+(len-4),"16BE")) return TagLib::String::UTF16BE;
++ }
++ return TagLib::String::Latin1ID3V2;
++ } else {
++ // Error or no-language configured: If Latin1ID3V2 is returned we normally will use the default unicode encoding unless Latin1 is selected by taglib
++ return TagLib::String::Latin1ID3V2;
++ }
++#endif /* HAVE_LIBRCC */
++ return TagLib::String::Latin1;
++}
+diff -dPNur taglib-1.9.1/taglib/toolkit/rccpatch.h taglib-1.9.1-ds/taglib/toolkit/rccpatch.h
+--- taglib-1.9.1/taglib/toolkit/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ taglib-1.9.1-ds/taglib/toolkit/rccpatch.h 2013-11-11 13:42:53.045126729 +0100
+@@ -0,0 +1,20 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <string.h>
++#include "tstring.h"
++#include "tbytevector.h"
++
++void rccTaglibPatchFree();
++void rccTaglibPatchInit();
++void rccTaglibPatchSetContext(void *newctx);
++
++TagLib::ByteVector rccTaglibPatchRecodeOutput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeInput(const std::string &s);
++TagLib::ByteVector rccTaglibPatchRecodeOutputID3(const std::string &s, bool v2 = false);
++TagLib::ByteVector rccTaglibPatchRecodeInputID3(const std::string &s, bool v2 = false);
++
++TagLib::String::Type rccTaglibPatchGetLocaleType();
++TagLib::String::Type rccTaglibPatchGetID3Type();
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur taglib-1.9.1/taglib/toolkit/tstring.cpp taglib-1.9.1-ds/taglib/toolkit/tstring.cpp
+--- taglib-1.9.1/taglib/toolkit/tstring.cpp 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/toolkit/tstring.cpp 2013-11-11 13:42:53.046126750 +0100
+@@ -29,6 +29,7 @@
+ #include <config.h>
+ #endif
+
++#include "rccpatch.h"
+ #include "tstring.h"
+ #include "tdebug.h"
+ #include "tstringlist.h"
+@@ -197,8 +198,11 @@
+ String::String(const std::string &s, Type t)
+ : d(new StringPrivate())
+ {
+- if(t == Latin1)
+- copyFromLatin1(&s[0], s.length());
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(&s[0], s.length(), true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(&s[0], s.length());
+ else {
+@@ -229,8 +233,11 @@
+ String::String(const char *s, Type t)
+ : d(new StringPrivate())
+ {
+- if(t == Latin1)
+- copyFromLatin1(s, ::strlen(s));
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(s, ::strlen(s), true, t);
+ else if(t == String::UTF8)
+ copyFromUTF8(s, ::strlen(s));
+ else {
+@@ -251,7 +258,10 @@
+ String::String(char c, Type t)
+ : d(new StringPrivate(1, static_cast<uchar>(c)))
+ {
+- if(t != Latin1 && t != UTF8) {
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t != Latin1 && t != Latin1ID3 && t != Latin1ID3V2 && t != UTF8) {
+ debug("String::String() -- A char should not contain UTF16.");
+ }
+ }
+@@ -262,8 +272,11 @@
+ if(v.isEmpty())
+ return;
+
+- if(t == Latin1)
+- copyFromLatin1(v.data(), v.size());
++ if(t == Locale)
++ t = rccTaglibPatchGetLocaleType();
++
++ if(t == Latin1 || t == Latin1ID3 || t == Latin1ID3V2)
++ copyFromLatin1(v.data(), v.size(), true, t);
+ else if(t == UTF8)
+ copyFromUTF8(v.data(), v.size());
+ else
+@@ -428,16 +441,46 @@
+
+ ByteVector String::data(Type t) const
+ {
+- switch(t)
+- {
++ ByteVector v;
++
++ if (t == Locale) {
++ // The source is either Unicode or real Latin1 (if rcc is bypassed)
++ std::string s = to8Bit(true);
++
++ // In case of UTF8 locale, this probably will return NULL (no recoding needed), but we will take UTF8 path in the next swtich
++ v = rccTaglibPatchRecodeOutput(s);
++ if (v.size()) return v;
++
++ t = rccTaglibPatchGetLocaleType();
++ }
++
++ switch(t) {
++ case Latin1ID3:
++ case Latin1ID3V2:
++ {
++ std::string s = to8Bit(true);
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeOutputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeOutputID3(s, true);
++ if (v.size())
++ return v;
++
++ // we don't know if we got NULL because rcc is disabled (error) or UTF8 output is required
++ if ((t == Latin1ID3V2)&&(rccTaglibPatchGetID3Type() == UTF8)) {
++ v.setData(s.c_str(), s.length());
++ } else {
++ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
++ v.append(char(*it));
++ }
++ return v;
++ }
+ case Latin1:
+ {
+ ByteVector v(size(), 0);
+ char *p = v.data();
+-
++
+ for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
+ *p++ = static_cast<char>(*it);
+-
++
+ return v;
+ }
+ case UTF8:
+@@ -763,12 +806,29 @@
+ // private members
+ ////////////////////////////////////////////////////////////////////////////////
+
+-void String::copyFromLatin1(const char *s, size_t length)
++void String::copyFromLatin1(const char *s, size_t length, bool prepare, Type t)
+ {
+ d->data.resize(length);
+-
+ for(size_t i = 0; i < length; ++i)
+ d->data[i] = static_cast<uchar>(s[i]);
++
++ // librcc conversation
++ if (prepare) {
++ std::string s = to8Bit(false);
++ ByteVector v;
++
++ if (t == Latin1ID3) v = rccTaglibPatchRecodeInputID3(s, false);
++ else if (t == Latin1ID3V2) v = rccTaglibPatchRecodeInputID3(s, true);
++ else /* Latin1 converted from Locale */ v = rccTaglibPatchRecodeInput(s);
++
++ if (v.size()) {
++ copyFromUTF8(v.data(), v.size());
++ } else {
++ // We don't know if we got UTF-8 encoded string or either rcc is disable or something is failed,
++ // since standard applications are really expecting here Latin1, it is safe to just check if we have violations of UTF8
++ //if (Unicode::isLegalUTF8(s)) t = UTF8;
++ }
++ }
+ }
+
+ void String::copyFromUTF8(const char *s, size_t length)
+@@ -874,7 +934,33 @@
+
+ std::ostream &operator<<(std::ostream &s, const TagLib::String &str)
+ {
+- s << str.to8Bit();
++ TagLib::ByteVector bv = str.data(TagLib::String::Locale);
++ s << bv;
+ return s;
+ }
+
++TagLib::String::Type TagLib::String::ID3Type(int i)
++{
++ if(i == Latin1)
++ return Latin1ID3V2;
++ return Type(i);
++};
++
++TagLib::String::Type TagLib::String::ID3WType(Type type)
++{
++ Type rcc_type = rccTaglibPatchGetID3Type();
++ if((rcc_type == Latin1ID3)||(rcc_type == Latin1ID3V2)||(rcc_type == Latin1)) {
++ if(type == Latin1) return
++ rcc_type;
++ return type;
++ }
++
++ return rcc_type;
++};
++
++TagLib::String::Type TagLib::String::ID3RealType(Type type)
++{
++ if((type == Latin1ID3) || (type == Latin1ID3V2))
++ return Latin1;
++ return type;
++}
+diff -dPNur taglib-1.9.1/taglib/toolkit/tstring.h taglib-1.9.1-ds/taglib/toolkit/tstring.h
+--- taglib-1.9.1/taglib/toolkit/tstring.h 2013-10-08 17:50:01.000000000 +0200
++++ taglib-1.9.1-ds/taglib/toolkit/tstring.h 2013-11-11 13:42:53.047126771 +0100
+@@ -90,6 +90,18 @@
+ */
+ enum Type {
+ /*!
++ * Determine using current locale settings
++ */
++ Locale = -1,
++ /*!
++ * Latin1 for ID3 tags.
++ */
++ Latin1ID3 = 65,
++ /*!
++ * Latin1 for ID3v2 tags.
++ */
++ Latin1ID3V2 = 66,
++ /*!
+ * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
+ */
+ Latin1 = 0,
+@@ -112,6 +124,10 @@
+ UTF16LE = 4
+ };
+
++ static Type ID3Type(int i);
++ static Type ID3WType(Type type);
++ static Type ID3RealType(Type type);
++
+ /*!
+ * Constructs an empty String.
+ */
+@@ -479,7 +495,7 @@
+ * 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);
++ void copyFromLatin1(const char *s, size_t length, bool prepare = false, Type t = Latin1);
+
+ /*!
+ * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order)