summaryrefslogtreecommitdiffstats
path: root/patches
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
downloadrusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.tar.gz
rusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.tar.bz2
rusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.tar.xz
rusxmms2-60bd665e74cfeeaf70882173a0dd56c883e2014a.zip
Added to git tree
Diffstat (limited to 'patches')
-rw-r--r--patches/gftp/gftp-ds-rcc.patch822
-rw-r--r--patches/gstreamer/gst-plugins-good-0.10.16-rusxmms.diff224
-rw-r--r--patches/gstreamer/gstreamer14
-rw-r--r--patches/gstreamer/libid3_problems3
-rw-r--r--patches/id3lib/id3lib-ds-rcc.patch169
-rw-r--r--patches/libid3tag/README2
-rw-r--r--patches/libid3tag/libid3tag-0.15.1b-ds-rcc.patch300
-rw-r--r--patches/libtranslate/README.txt5
-rw-r--r--patches/libtranslate/libtranslate-ds2-memory.patch12
-rw-r--r--patches/libtranslate/libtranslate-ds3-charsetparse.patch47
-rw-r--r--patches/libtranslate/libtranslate-ds4-condfix.patch38
-rw-r--r--patches/libtranslate/libtranslate-ds5-empty.patch17
-rw-r--r--patches/libtranslate/libtranslate-ds6-promt.patch27
-rw-r--r--patches/libtranslate/libtranslate-ds7-fixcharset.patch93
-rw-r--r--patches/libtranslate/services.xml258
-rw-r--r--patches/libtranslate/soup22/libtranslate-ds1-timed.patch352
-rw-r--r--patches/libtranslate/soup24/libtranslate-ds1-timed24.patch360
-rw-r--r--patches/libtranslate/soup24/libtranslate-ds8-soup24inc.patch533
-rw-r--r--patches/mpg123/mpg123-ds-rcc.patch151
-rw-r--r--patches/mpg123/mpg123-ds-rcc1121.patch247
-rw-r--r--patches/mpg123/mpg123-ds-rcc173.patch271
-rw-r--r--patches/mpg123/mpg123-ds-rcc65.patch240
-rw-r--r--patches/p7zip/README13
-rw-r--r--patches/p7zip/p7zip_4.44-ds-rusxmms-full.patch314
-rw-r--r--patches/p7zip/p7zip_4.57-ds-rusxmms-full.patch419
-rw-r--r--patches/p7zip/p7zip_4.57-ds-rusxmms.patch336
-rw-r--r--patches/p7zip/p7zip_4.65-ds-rusxmms-full.patch425
-rw-r--r--patches/p7zip/p7zip_4.65-ds-rusxmms.patch305
-rw-r--r--patches/p7zip/p7zip_9.04-ds-rusxmms-full.patch414
-rw-r--r--patches/p7zip/p7zip_9.04-ds-rusxmms.patch294
-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
-rw-r--r--patches/unzip/README30
-rw-r--r--patches/unzip/unzip-5.52-ds-rusxmms.patch159
-rw-r--r--patches/unzip/unzip-5.52-ds-rusxmms2.patch149
-rw-r--r--patches/unzip/unzip-ds-unixenc.patch9
-rw-r--r--patches/unzip/unzip60-ds-isprint.patch12
-rwxr-xr-xpatches/unzip/update_lazy9
-rwxr-xr-xpatches/unzip/update_shared9
-rw-r--r--patches/xmms-plugins/xmms-wma-csa1.tar.bz2bin0 -> 20480 bytes
-rw-r--r--patches/xmms/extra/xmms-ds-mpg123-wrongencoding.patch157
-rw-r--r--patches/xmms/plugins/xmms-ds-mpg123-editor-keys.patch164
-rw-r--r--patches/xmms/plugins/xmms-ds-mpg123-editor.patch202
-rw-r--r--patches/xmms/plugins/xmms-ds-mpg123.patch20
-rw-r--r--patches/xmms/plugins/xmms-ds-vorbis-editor-keys.patch78
-rw-r--r--patches/xmms/plugins/xmms-ds-vorbis-editor.patch51
-rw-r--r--patches/xmms/xmms-ds-playlist.patch526
-rw-r--r--patches/xmms/xmms-ds-rusxmms-charset.patch87
-rw-r--r--patches/xmms/xmms-ds-rusxmms.patch172
-rw-r--r--patches/xmms/xmms-ds-shade.patch194
-rw-r--r--patches/xmms/xmms-ds-textbox.patch31
62 files changed, 15850 insertions, 0 deletions
diff --git a/patches/gftp/gftp-ds-rcc.patch b/patches/gftp/gftp-ds-rcc.patch
new file mode 100644
index 0000000..a704deb
--- /dev/null
+++ b/patches/gftp/gftp-ds-rcc.patch
@@ -0,0 +1,822 @@
+diff -dPNur gftp-2.0.18-orig/configure.in gftp-2.0.18-new/configure.in
+--- gftp-2.0.18-orig/configure.in 2005-02-04 16:42:32.000000000 +0100
++++ gftp-2.0.18-new/configure.in 2005-07-23 18:54:53.000000000 +0200
+@@ -288,6 +288,20 @@
+ fi
+ AC_SUBST(SSL_LIBS)
+
++AC_CHECK_LIB(rccui, rccUiInit,[
++ AC_CHECK_HEADERS(librcc.h librccui.h,[
++ LIBRCC_LIBS="-lrccui"
++ LIBRCC_INCLUDES="-DHAVE_LIBRCC"
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
++
+ AM_GNU_GETTEXT
+
+ AC_CHECK_PROG(DB2HTML, db2html, true, false)
+diff -dPNur gftp-2.0.18-orig/lib/gftp.h gftp-2.0.18-new/lib/gftp.h
+--- gftp-2.0.18-orig/lib/gftp.h 2005-01-19 00:09:58.000000000 +0100
++++ gftp-2.0.18-new/lib/gftp.h 2005-07-23 20:57:03.000000000 +0200
+@@ -362,6 +362,7 @@
+ {
+ int protonum; /* Current number of the protocol this is
+ set to */
++ int language, charset; /* Remote language and encoding */
+ char *hostname, /* Hostname we will connect to */
+ *username, /* Username for host*/
+ *password, /* Password for host */
+@@ -928,6 +929,12 @@
+ const char *filename,
+ mode_t * mode );
+
++void gftp_set_language ( gftp_request * request,
++ int language );
++
++void gftp_set_charset ( gftp_request * request,
++ int charset );
++
+ void gftp_set_hostname ( gftp_request * request,
+ const char *hostname );
+
+diff -dPNur gftp-2.0.18-orig/lib/Makefile.am gftp-2.0.18-new/lib/Makefile.am
+--- gftp-2.0.18-orig/lib/Makefile.am 2005-01-16 17:10:12.000000000 +0100
++++ gftp-2.0.18-new/lib/Makefile.am 2005-07-23 18:58:12.000000000 +0200
+@@ -4,6 +4,6 @@
+ noinst_LIBRARIES = libgftp.a
+ libgftp_a_SOURCES=bookmark.c cache.c config_file.c fsp.c ftps.c https.c \
+ local.c misc.c mkstemps.c protocols.c pty.c rfc959.c \
+- rfc2068.c sshv2.c sslcommon.c
+-INCLUDES=@GLIB_CFLAGS@ @PTHREAD_CFLAGS@ -I../intl -DSHARE_DIR=\"$(datadir)/gftp\" -DLOCALE_DIR=\"$(datadir)/locale\"
+-noinst_HEADERS=gftp.h ftpcommon.h httpcommon.h options.h
++ rfc2068.c sshv2.c sslcommon.c rcc.c
++INCLUDES=@LIBRCC_INCLUDES@ @GLIB_CFLAGS@ @PTHREAD_CFLAGS@ -I../intl -DSHARE_DIR=\"$(datadir)/gftp\" -DLOCALE_DIR=\"$(datadir)/locale\"
++noinst_HEADERS=gftp.h ftpcommon.h httpcommon.h options.h rcc.h
+diff -dPNur gftp-2.0.18-orig/lib/rcc.c gftp-2.0.18-new/lib/rcc.c
+--- gftp-2.0.18-orig/lib/rcc.c 1970-01-01 01:00:00.000000000 +0100
++++ gftp-2.0.18-new/lib/rcc.c 2005-07-24 01:53:25.000000000 +0200
+@@ -0,0 +1,289 @@
++#include <stdlib.h>
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++# include <librccui.h>
++#endif /* HAVE_LIBRCC */
++
++#include "rcc.h"
++
++#ifdef HAVE_LIBRCC
++static rcc_class classes[] = {
++ { "ftp", RCC_CLASS_STANDARD, NULL, NULL, "FTP Encoding", 0 },
++ { "http", RCC_CLASS_STANDARD, NULL, NULL, "HTTP Encoding", 0 },
++ { "ssh", RCC_CLASS_STANDARD, NULL, NULL, "SSH Encoding", 0 },
++ { "fs", RCC_CLASS_STANDARD, NULL, NULL, "FS Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, NULL, NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++rcc_context ctx;
++rcc_ui_context uictx;
++static int rcc_initialized = 0;
++#endif /* HAVE_LIBRCC */
++
++
++void rccPatchFree() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ rccUiFreeContext(uictx);
++ rccFreeContext(ctx);
++ rccUiFree();
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++void rccPatchInit() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ rccInit();
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) {
++ rccLoad(ctx, "ftp");
++ rccInitDb4(ctx, NULL, 0);
++ rccUiInit();
++ uictx = rccUiCreateContext(ctx);
++ if (uictx) rcc_initialized = 1;
++ else {
++ rccUiFree();
++ rccFreeContext(ctx);
++ rccFree();
++ }
++ } else rccFree();
++#endif /* HAVE_LIBRCC */
++}
++
++
++#ifdef HAVE_LIBRCC
++static char *rcc_languages[RCC_MAX_LANGUAGES+1];
++static char *rcc_charsets[RCC_MAX_CHARSETS+1];
++#endif /* HAVE_LIBRCC */
++
++char **rccPatchGetLanguageList() {
++#ifdef HAVE_LIBRCC
++ unsigned int i, num;
++
++ if (rcc_initialized) {
++ num = rccGetLanguageNumber(ctx);
++ for (i=0;i<(num?num:1);i++)
++ rcc_languages[i] = (char*)rccUiGetLanguageName(uictx, (rcc_language_id)i);
++
++ rcc_languages[i] = NULL;
++ return rcc_languages;
++ }
++#endif /* HAVE_LIBRCC */
++
++ return NULL;
++
++}
++
++char **rccPatchGetCharsetList(int lid) {
++#ifdef HAVE_LIBRCC
++ unsigned int i, num;
++ rcc_language_config config;
++
++ if (rcc_initialized) {
++ config = rccGetConfig(ctx, (rcc_language_id)lid);
++ num = rccConfigGetCharsetNumber(config);
++ for (i=0;i<(num?num:1);i++)
++ rcc_charsets[i] = (char*)rccUiGetCharsetName(uictx, (rcc_language_id)lid, (rcc_class_id)0 /* first class, they are equal*/, (rcc_charset_id)i);
++
++ rcc_charsets[i] = NULL;
++ return rcc_charsets;
++ }
++#endif /* HAVE_LIBRCC */
++
++ return NULL;
++}
++
++char *rccPatchFrom(gftp_request * request, const char *str) {
++#ifdef HAVE_LIBRCC
++ rcc_class_id cl;
++ if (rcc_initialized) {
++ switch (request->protonum) {
++ case GFTP_FTP_NUM:
++ case GFTP_FTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FTP;
++ break;
++ case GFTP_HTTP_NUM:
++ case GFTP_HTTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_HTTP;
++ break;
++ case GFTP_SSHV2_NUM:
++ cl = (rcc_class_id)RCC_CLASS_SSH;
++ break;
++ case GFTP_LOCAL_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FS;
++ break;
++ default:
++ return NULL;
++ }
++
++ if ((cl == RCC_CLASS_FTP)||(cl == RCC_CLASS_HTTP)||(cl == RCC_CLASS_SSH)) {
++ if (request->language) rccSetLanguage(ctx, (rcc_language_id)request->language);
++ if (request->charset) rccSetCharset(ctx, cl, (rcc_charset_id)request->charset);
++ }
++
++ return rccRecodeFromCharset(ctx, cl, "UTF-8", str);
++ }
++#endif /* HAVE_LIBRCC */
++ return NULL;
++}
++
++char *rccPatchTo(gftp_request * request, const char *str) {
++#ifdef HAVE_LIBRCC
++ rcc_class_id cl;
++ if (rcc_initialized) {
++ switch (request->protonum) {
++ case GFTP_FTP_NUM:
++ case GFTP_FTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FTP;
++ break;
++ case GFTP_HTTP_NUM:
++ case GFTP_HTTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_HTTP;
++ break;
++ case GFTP_SSHV2_NUM:
++ cl = (rcc_class_id)RCC_CLASS_SSH;
++ break;
++ case GFTP_LOCAL_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FS;
++ break;
++ default:
++ return NULL;
++ }
++
++ if ((cl == RCC_CLASS_FTP)||(cl == RCC_CLASS_HTTP)||(cl == RCC_CLASS_SSH)) {
++ if (request->language) rccSetLanguage(ctx, (rcc_language_id)request->language);
++ if (request->charset) rccSetCharset(ctx, cl, (rcc_charset_id)request->charset);
++ }
++
++ return rccRecodeToCharset(ctx, cl, "UTF-8", str);
++ }
++#endif /* HAVE_LIBRCC */
++ return NULL;
++}
++
++char *rccPatch(gftp_request *from, gftp_request *to, const char *str) {
++ char *res, *ret;
++ const char *tmp;
++
++ if (from->protonum == to->protonum) return NULL;
++ printf("%u %u\n", from->protonum, to->protonum);
++
++ tmp = strstr(str, to->directory);
++ if (!tmp) tmp = str;
++
++ res = rccPatchTo(from, tmp);
++ if (!res) res = (char*)tmp;
++
++ ret = rccPatchFrom(to, res);
++ if (ret) {
++ if (res!=tmp) free(res);
++ } else {
++ if (res!=tmp) ret = res;
++ else return NULL;
++ }
++
++ if (tmp != str) {
++ res = (char*)malloc((strlen(ret) + (tmp-str) + 1)*sizeof(char));
++ if (res) {
++ memcpy(res, str, (tmp-str));
++ strcpy(res+(tmp-str), ret);
++ }
++ free(ret);
++ if (res) puts(res);
++ return res;
++ }
++
++ return ret;
++}
++
++char *rccPatchFromClass(gftp_request * request, int from, const char *str) {
++#ifdef HAVE_LIBRCC
++ rcc_class_id cl;
++ if (rcc_initialized) {
++ switch (request->protonum) {
++ case GFTP_FTP_NUM:
++ case GFTP_FTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FTP;
++ break;
++ case GFTP_HTTP_NUM:
++ case GFTP_HTTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_HTTP;
++ break;
++ case GFTP_SSHV2_NUM:
++ cl = (rcc_class_id)RCC_CLASS_SSH;
++ break;
++ case GFTP_LOCAL_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FS;
++ break;
++ default:
++ return NULL;
++ }
++
++ if ((cl == RCC_CLASS_FTP)||(cl == RCC_CLASS_HTTP)||(cl == RCC_CLASS_SSH)) {
++ if (request->language) rccSetLanguage(ctx, (rcc_language_id)request->language);
++ if (request->charset) rccSetCharset(ctx, cl, (rcc_charset_id)request->charset);
++ }
++
++ return rccRecode(ctx, (rcc_class_id)from, cl, str);
++ }
++#endif /* HAVE_LIBRCC */
++ return NULL;
++}
++
++char *rccPatchToClass(gftp_request * request, int to, const char *str) {
++#ifdef HAVE_LIBRCC
++ rcc_class_id cl;
++ if (rcc_initialized) {
++ switch (request->protonum) {
++ case GFTP_FTP_NUM:
++ case GFTP_FTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FTP;
++ break;
++ case GFTP_HTTP_NUM:
++ case GFTP_HTTPS_NUM:
++ cl = (rcc_class_id)RCC_CLASS_HTTP;
++ break;
++ case GFTP_SSHV2_NUM:
++ cl = (rcc_class_id)RCC_CLASS_SSH;
++ break;
++ case GFTP_LOCAL_NUM:
++ cl = (rcc_class_id)RCC_CLASS_FS;
++ break;
++ default:
++ return NULL;
++ }
++
++ if ((cl == RCC_CLASS_FTP)||(cl == RCC_CLASS_HTTP)||(cl == RCC_CLASS_SSH)) {
++ if (request->language) rccSetLanguage(ctx, (rcc_language_id)request->language);
++ if (request->charset) rccSetCharset(ctx, cl, (rcc_charset_id)request->charset);
++ }
++
++ return rccRecode(ctx, cl, (rcc_class_id)to, str);
++ }
++#endif /* HAVE_LIBRCC */
++ return NULL;
++}
++
++
++char *rccPatchUTF2OUT(const char *str) {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ return rccRecodeFromCharset(ctx, RCC_CLASS_OUT, "UTF-8", str);
++ }
++#endif /* HAVE_LIBRCC */
++ return NULL;
++}
++
++char *rccPatchOUT2UTF(const char *str) {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ return rccRecodeToCharset(ctx, RCC_CLASS_OUT, "UTF-8", str);
++ }
++#endif /* HAVE_LIBRCC */
++ return NULL;
++}
+diff -dPNur gftp-2.0.18-orig/lib/rcc.h gftp-2.0.18-new/lib/rcc.h
+--- gftp-2.0.18-orig/lib/rcc.h 1970-01-01 01:00:00.000000000 +0100
++++ gftp-2.0.18-new/lib/rcc.h 2005-07-24 01:49:20.000000000 +0200
+@@ -0,0 +1,28 @@
++#ifndef _RCC_H
++#define _RCC_H
++
++#include "gftp.h"
++
++#define RCC_CLASS_FTP 0
++#define RCC_CLASS_HTTP 1
++#define RCC_CLASS_SSH 2
++#define RCC_CLASS_FS 3
++#define RCC_CLASS_OUT 4
++
++void rccPatchFree();
++void rccPatchInit();
++
++char **rccPatchGetLanguageList();
++char **rccPatchGetCharsetList(int lid);
++
++char *rccPatchFrom(gftp_request * request, const char *str);
++char *rccPatchTo(gftp_request * request, const char *str);
++char *rccPatch(gftp_request *from, gftp_request *to, const char *str);
++
++char *rccPatchFromClass(gftp_request * request, int from, const char *str);
++char *rccPatchToClass(gftp_request * request, int to, const char *str);
++
++char *rccPatchUTF2OUT(const char *str);
++char *rccPatchOUT2UTF(const char *str);
++
++#endif /* _RCC_H */
+diff -dPNur gftp-2.0.18-orig/src/gtk/gtkui.c gftp-2.0.18-new/src/gtk/gtkui.c
+--- gftp-2.0.18-orig/src/gtk/gtkui.c 2005-01-26 04:22:05.000000000 +0100
++++ gftp-2.0.18-new/src/gtk/gtkui.c 2005-07-24 00:40:47.000000000 +0200
+@@ -351,6 +351,8 @@
+ filelist = wdata->files;
+ templist = get_next_selection (templist, &filelist, &num);
+ curfle = filelist->data;
++ cdata->source_string = gftp_string_to_utf8(wdata->request, curfle->file);
++ if (!cdata->source_string)
+ cdata->source_string = g_strdup (curfle->file);
+
+ tempstr = g_strdup_printf (_("What would you like to rename %s to?"),
+diff -dPNur gftp-2.0.18-orig/src/gtk/Makefile.am gftp-2.0.18-new/src/gtk/Makefile.am
+--- gftp-2.0.18-orig/src/gtk/Makefile.am 2005-01-16 17:12:08.000000000 +0100
++++ gftp-2.0.18-new/src/gtk/Makefile.am 2005-07-23 19:16:26.000000000 +0200
+@@ -5,6 +5,6 @@
+ gftp_gtk_SOURCES = bookmarks.c chmod_dialog.c delete_dialog.c dnd.c \
+ gftp-gtk.c gtkui.c gtkui_transfer.c menu-items.c \
+ misc-gtk.c options_dialog.c transfer.c view_dialog.c
+-INCLUDES = @GTK_CFLAGS@ @PTHREAD_CFLAGS@ -I../../intl
+-LDADD = ../../lib/libgftp.a ../../lib/fsplib/libfsp.a ../uicommon/libgftpui.a @GTK_LIBS@ @PTHREAD_LIBS@ @EXTRA_LIBS@ @GTHREAD_LIBS@ @SSL_LIBS@ @LIBINTL@
++INCLUDES = @LIBRCC_INCLUDES@ @GTK_CFLAGS@ @PTHREAD_CFLAGS@ -I../../intl
++LDADD = ../../lib/libgftp.a ../../lib/fsplib/libfsp.a ../uicommon/libgftpui.a @GTK_LIBS@ @PTHREAD_LIBS@ @EXTRA_LIBS@ @GTHREAD_LIBS@ @SSL_LIBS@ @LIBINTL@ @LIBRCC_LIBS@
+ noinst_HEADERS = gftp-gtk.h
+diff -dPNur gftp-2.0.18-orig/src/text/gftp-text.c gftp-2.0.18-new/src/text/gftp-text.c
+--- gftp-2.0.18-orig/src/text/gftp-text.c 2005-01-25 02:11:00.000000000 +0100
++++ gftp-2.0.18-new/src/text/gftp-text.c 2005-07-24 01:54:25.000000000 +0200
+@@ -18,6 +18,7 @@
+ /*****************************************************************************/
+
+ #include "gftp-text.h"
++#include "../../lib/rcc.h"
+ static const char cvsid[] = "$Id: gftp-text.c,v 1.45 2005/01/25 01:11:00 masneyb Exp $";
+
+ unsigned int
+@@ -93,6 +94,7 @@
+ const char *string, ...)
+ {
+ char tempstr[512], *utf8_str = NULL, *outstr;
++ char *locale_str;
+ va_list argp;
+
+ g_return_if_fail (string != NULL);
+@@ -140,7 +142,14 @@
+ }
+
+ if (level == gftp_logging_misc_nolog)
++{
++ locale_str = rccPatchUTF2OUT(outstr);
++ if (locale_str) {
++ printf ("%s", locale_str);
++ free(locale_str);
++ } else
+ printf ("%s", outstr);
++}
+ else
+ gftp_text_write_string (request, outstr);
+
+@@ -158,6 +167,7 @@
+ gchar *locale_question;
+ sigset_t sig, sigsave;
+ char *pos, *termname;
++ char *tmp;
+ int singlechar;
+ FILE *infd;
+
+@@ -247,6 +257,9 @@
+ #else
+ char tempstr[512];
+ #endif
++ char *recoded = NULL;
++
++ rccPatchInit();
+
+ gftpui_common_init (&argc, &argv, gftp_text_log);
+
+@@ -298,9 +311,11 @@
+ g_snprintf (prompt, sizeof (prompt), "%sftp%s> ", GFTPUI_COMMON_COLOR_BLUE, GFTPUI_COMMON_COLOR_DEFAULT);
+ while ((tempstr = readline (prompt)))
+ {
++ if (recoded) free(recoded);
++ recoded = rccPatchFromClass(gftp_text_remreq, RCC_CLASS_OUT, tempstr);
+ if (gftpui_common_process_command (locuidata, gftp_text_locreq,
+ remuidata, gftp_text_remreq,
+- tempstr) == 0)
++ recoded?recoded:tempstr) == 0)
+ break;
+
+ add_history (tempstr);
+@@ -310,16 +325,20 @@
+ printf ("%sftp%s> ", GFTPUI_COMMON_COLOR_BLUE, GFTPUI_COMMON_COLOR_DEFAULT);
+ while (fgets (tempstr, sizeof (tempstr), stdin) != NULL)
+ {
++ if (recoded) free(recoded);
++ recoded = rccPatchFromClass(gftp_tetxt_remreq, RCC_CLASS_OUT, tempstr);
+ if (gftpui_common_process_command (locuidata, gftp_text_locreq,
+ remuidata, gftp_text_remreq,
+- tempstr) == 0)
++ recoded?recoded:tempstr) == 0)
+ break;
+
+ printf ("%sftp%s> ", GFTPUI_COMMON_COLOR_BLUE, GFTPUI_COMMON_COLOR_DEFAULT);
+ }
+ #endif
+-
++ if (recoded) free(recoded);
++
+ gftp_shutdown ();
++ rccPatchFree();
+ return (0);
+ }
+
+diff -dPNur gftp-2.0.18-orig/src/text/Makefile.am gftp-2.0.18-new/src/text/Makefile.am
+--- gftp-2.0.18-orig/src/text/Makefile.am 2005-01-16 17:12:00.000000000 +0100
++++ gftp-2.0.18-new/src/text/Makefile.am 2005-07-23 19:16:39.000000000 +0200
+@@ -3,7 +3,7 @@
+ bin_PROGRAMS = @GFTP_TEXT@
+ EXTRA_PROGRAMS = gftp-text
+ gftp_text_SOURCES=gftp-text.c textui.c
+-INCLUDES=@GLIB_CFLAGS@ -I../../intl
+-LDADD = ../../lib/libgftp.a ../../lib/fsplib/libfsp.a ../uicommon/libgftpui.a @GLIB_LIBS@ @EXTRA_LIBS@ @READLINE_LIBS@ @SSL_LIBS@ @LIBINTL@
++INCLUDES=@LIBRCC_INCLUDES@ @GLIB_CFLAGS@ -I../../intl
++LDADD = ../../lib/libgftp.a ../../lib/fsplib/libfsp.a ../uicommon/libgftpui.a @GLIB_LIBS@ @EXTRA_LIBS@ @READLINE_LIBS@ @SSL_LIBS@ @LIBINTL@ @LIBRCC_LIBS@
+ noinst_HEADERS=gftp-text.h
+ localedir=$(datadir)/locale
+diff -dPNur gftp-2.0.18-orig/lib/protocols.c gftp-2.0.18-new/lib/protocols.c
+--- gftp-2.0.18-orig/lib/protocols.c 2005-07-23 15:30:59.000000000 +0200
++++ gftp-2.0.18-new/lib/protocols.c 2005-07-24 00:56:12.000000000 +0200
+@@ -18,6 +18,8 @@
+ /*****************************************************************************/
+
+ #include "gftp.h"
++#include "rcc.h"
++
+ static const char cvsid[] = "$Id: protocols.c,v 1.125 2005/01/25 02:34:18 masneyb Exp $";
+
+ gftp_request *
+@@ -26,6 +28,8 @@
+ gftp_request *request;
+
+ request = g_malloc0 (sizeof (*request));
++ request->language = 0;
++ request->charset = 0;
+ request->datafd = -1;
+ request->cachefd = -1;
+ request->server_type = GFTP_DIRTYPE_OTHER;
+@@ -460,6 +469,9 @@
+ gftp_lookup_request_option (request, "remote_charsets", &tempstr);
+ if (*tempstr == '\0')
+ {
++ ret = rccPatchTo(request, str);
++ if (ret) return ret;
++
+ error = NULL;
+ if ((ret = g_locale_to_utf8 (str, -1, &bread, &bwrite, &error)) != NULL)
+ return (ret);
+@@ -531,6 +544,9 @@
+ gftp_lookup_request_option (request, "remote_charsets", &tempstr);
+ if (*tempstr == '\0')
+ {
++ ret = rccPatchFrom(request, str);
++ if (ret) return ret;
++
+ error = NULL;
+ if ((ret = g_locale_from_utf8 (str, -1, &bread, &bwrite, &error)) != NULL)
+ return (ret);
+@@ -919,6 +935,18 @@
+ }
+
+
++void
++gftp_set_language (gftp_request * request, int language) {
++ g_return_if_fail (request != NULL);
++ request->language = language;
++}
++
++void
++gftp_set_charset (gftp_request * request, int charset) {
++ g_return_if_fail (request != NULL);
++ request->charset = charset;
++}
++
+ void
+ gftp_set_hostname (gftp_request * request, const char *hostname)
+ {
+@@ -1056,6 +1084,7 @@
+ const char *newname)
+ {
+ char *utf8;
++ char *oldutf8;
+ int ret;
+
+ g_return_val_if_fail (request != NULL, GFTP_EFATAL);
+@@ -1064,13 +1093,13 @@
+ return (GFTP_EFATAL);
+
+ utf8 = gftp_string_from_utf8 (request, newname);
++ oldutf8 = gftp_string_from_utf8 (request, oldname);
++ ret = request->rename (request, oldutf8?oldutf8:oldname, utf8?utf8:newname);
++
+ if (utf8 != NULL)
+- {
+- ret = request->rename (request, oldname, utf8);
+ g_free (utf8);
+- }
+- else
+- ret = request->rename (request, oldname, newname);
++ if (oldutf8 != NULL)
++ g_free (oldutf8);
+
+ return (ret);
+ }
+@@ -1948,11 +1977,14 @@
+ (newsize = g_hash_table_lookup (dirhash, fle->file)) != NULL)
+ fle->startsize = *newsize;
+
+- if (transfer->toreq && fle->destfile == NULL)
++ if (transfer->toreq && fle->destfile == NULL) {
++ newname = rccPatch(transfer->fromreq, transfer->toreq, fle->file);
+ fle->destfile = gftp_build_path (transfer->toreq,
+ transfer->toreq->directory,
+- fle->file, NULL);
+-
++ newname?newname:fle->file, NULL);
++ if (newname) free(newname);
++ }
++
+ if (transfer->fromreq->directory != NULL &&
+ *transfer->fromreq->directory != '\0' &&
+ *fle->file != '/')
+@@ -2026,11 +2058,15 @@
+ return (curfle->size);
+ }
+
+- if (transfer->toreq && curfle->destfile == NULL)
++ if (transfer->toreq && curfle->destfile == NULL) {
++ newname = rccPatch(transfer->fromreq, transfer->toreq, curfle->file);
+ curfle->destfile = gftp_build_path (transfer->toreq,
+ transfer->toreq->directory,
+- curfle->file, NULL);
++ newname?newname:curfle->file, NULL);
++ if (newname) free(newname);
++ }
+
++
+ if (transfer->fromreq->directory != NULL &&
+ *transfer->fromreq->directory != '\0' && *curfle->file != '/')
+ {
+diff -dPNur gftp-2.0.18-orig/src/gtk/gftp-gtk.c gftp-2.0.18-new/src/gtk/gftp-gtk.c
+--- gftp-2.0.18-orig/src/gtk/gftp-gtk.c 2005-01-25 03:34:19.000000000 +0100
++++ gftp-2.0.18-new/src/gtk/gftp-gtk.c 2005-07-23 22:22:42.000000000 +0200
+@@ -18,6 +18,7 @@
+ /*****************************************************************************/
+
+ #include "gftp-gtk.h"
++#include "../../lib/rcc.h"
+ static const char cvsid[] = "$Id: gftp-gtk.c,v 1.66 2005/01/25 02:34:19 masneyb Exp $";
+
+ static GtkItemFactory *log_factory, *dl_factory;
+@@ -28,6 +29,7 @@
+ GtkWidget * stop_btn, * hostedit, * useredit, * passedit, * portedit, * logwdw,
+ * dlwdw, * protocol_menu, * optionmenu, * gftpui_command_widget,
+ * download_left_arrow, * upload_right_arrow, * openurl_btn;
++GtkWidget * language_menu, * charset_menu;
+ GtkTooltips * openurl_tooltip;
+ GtkAdjustment * logwdw_vadj;
+ #if GTK_MAJOR_VERSION > 1
+@@ -420,6 +422,42 @@
+ return (factory->widget);
+ }
+
++#ifdef HAVE_LIBRCC
++static int rcc_current_language = 0;
++static int rcc_current_charset = 0;
++
++static void rccCharsetCB(GtkWidget * w, gpointer item) {
++ rcc_current_charset = g_list_index(GTK_MENU_SHELL(charset_menu)->children, gtk_menu_get_active(GTK_MENU(charset_menu)));
++}
++
++static void rccLanguageCB(GtkWidget * w, gpointer item) {
++ GtkWidget *tempwid, *optionmenu;
++ unsigned int i;
++ char **langs;
++ gint cur;
++
++ cur = g_list_index(GTK_MENU_SHELL(language_menu)->children, gtk_menu_get_active(GTK_MENU(language_menu)));
++ optionmenu = gtk_menu_get_attach_widget(GTK_MENU(charset_menu));
++
++ rcc_current_language = cur;
++ rcc_current_charset = 0;
++
++ langs = rccPatchGetCharsetList(cur);
++ if (langs) {
++ charset_menu = gtk_menu_new ();
++ for (i=0;langs[i];i++) {
++ tempwid = gtk_menu_item_new_with_label (langs[i]);
++ gtk_object_set_user_data (GTK_OBJECT (tempwid), GINT_TO_POINTER(i));
++ gtk_menu_append (GTK_MENU (charset_menu), tempwid);
++ gtk_widget_show (tempwid);
++ }
++
++ gtk_option_menu_remove_menu (GTK_OPTION_MENU (optionmenu));
++ gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), charset_menu);
++ gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), 0);
++ }
++}
++#endif /* HAVE_LIBRCC */
+
+ static GtkWidget *
+ CreateConnectToolbar (GtkWidget * parent)
+@@ -430,14 +468,19 @@
+ {"application/x-rootwin-drop", 0, 1}
+ };
+ GtkWidget *toolbar, *box, *tempwid;
++ GtkWidget *vbox;
++ GtkWidget *tmpoptionmenu;
+ gftp_config_list_vars * tmplistvar;
+ char *default_protocol, *tempstr;
++ char **langs;
+ int i, num;
+
+ toolbar = gtk_handle_box_new ();
+
++ vbox = gtk_vbox_new (FALSE, 0);
+ box = gtk_hbox_new (FALSE, 4);
+- gtk_container_add (GTK_CONTAINER (toolbar), box);
++ gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 0);
++ gtk_container_add (GTK_CONTAINER (toolbar), vbox);
+ gtk_container_border_width (GTK_CONTAINER (box), 5);
+
+ openurl_tooltip = gtk_tooltips_new ();
+@@ -548,6 +591,7 @@
+ optionmenu = gtk_option_menu_new ();
+ gtk_box_pack_start (GTK_BOX (tempwid), optionmenu, TRUE, FALSE, 0);
+
++
+ num = 0;
+ gftp_lookup_global_option ("default_protocol", &default_protocol);
+ protocol_menu = gtk_menu_new ();
+@@ -584,6 +628,61 @@
+ gtk_container_border_width (GTK_CONTAINER (stop_btn), 1);
+ gtk_box_pack_start (GTK_BOX (box), stop_btn, FALSE, FALSE, 0);
+
++#ifdef HAVE_LIBRCC
++ box = gtk_hbox_new (FALSE, 4);
++ gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 0);
++ gtk_container_border_width (GTK_CONTAINER (box), 5);
++
++ langs = rccPatchGetCharsetList(0);
++ if (langs) {
++ tempwid = gtk_vbox_new (FALSE, 0);
++ gtk_box_pack_end (GTK_BOX (box), tempwid, FALSE, FALSE, 0);
++
++ tmpoptionmenu = gtk_option_menu_new ();
++ gtk_box_pack_start (GTK_BOX (tempwid), tmpoptionmenu, TRUE, FALSE, 0);
++
++ charset_menu = gtk_menu_new ();
++ for (i=0;langs[i];i++) {
++ tempwid = gtk_menu_item_new_with_label (langs[i]);
++ gtk_signal_connect(GTK_OBJECT(tempwid), "activate", GTK_SIGNAL_FUNC(rccCharsetCB), NULL);
++ gtk_object_set_user_data (GTK_OBJECT (tempwid), GINT_TO_POINTER(i));
++ gtk_menu_append (GTK_MENU (charset_menu), tempwid);
++ gtk_widget_show (tempwid);
++ }
++
++ gtk_option_menu_set_menu (GTK_OPTION_MENU (tmpoptionmenu), charset_menu);
++ gtk_option_menu_set_history (GTK_OPTION_MENU (tmpoptionmenu), rcc_current_charset);
++
++ tempwid = gtk_label_new (_("Charset: "));
++ gtk_box_pack_end (GTK_BOX (box), tempwid, FALSE, FALSE, 0);
++ }
++
++ langs = rccPatchGetLanguageList();
++ if (langs) {
++ tempwid = gtk_vbox_new (FALSE, 0);
++ gtk_box_pack_end (GTK_BOX (box), tempwid, FALSE, FALSE, 0);
++
++ tmpoptionmenu = gtk_option_menu_new ();
++ gtk_box_pack_start (GTK_BOX (tempwid), tmpoptionmenu, TRUE, FALSE, 0);
++
++ language_menu = gtk_menu_new ();
++ for (i=0;langs[i];i++) {
++ tempwid = gtk_menu_item_new_with_label (langs[i]);
++ gtk_signal_connect(GTK_OBJECT(tempwid), "activate", GTK_SIGNAL_FUNC(rccLanguageCB), NULL);
++ gtk_object_set_user_data (GTK_OBJECT (tempwid), GINT_TO_POINTER(i));
++ gtk_menu_append (GTK_MENU (language_menu), tempwid);
++ gtk_widget_show (tempwid);
++ }
++
++ gtk_option_menu_set_menu (GTK_OPTION_MENU (tmpoptionmenu), language_menu);
++ gtk_option_menu_set_history (GTK_OPTION_MENU (tmpoptionmenu), rcc_current_language);
++
++ tempwid = gtk_label_new (_("Language: "));
++ gtk_box_pack_end (GTK_BOX (box), tempwid, FALSE, FALSE, 0);
++ }
++#endif /* HAVE_LIBRCC */
++
++
+ gtk_widget_grab_focus (GTK_COMBO (hostedit)->entry);
+
+ return (toolbar);
+@@ -1132,6 +1231,16 @@
+ add_history (current_wdata->combo, current_wdata->history,
+ current_wdata->histlen, current_wdata->request->directory);
+
++#ifdef HAVE_LIBRCC
++ tempwid = gtk_menu_get_active (GTK_MENU (language_menu));
++ num = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (tempwid)));
++ gftp_set_language(current_wdata->request, num);
++
++ tempwid = gtk_menu_get_active (GTK_MENU (charset_menu));
++ num = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (tempwid)));
++ gftp_set_charset(current_wdata->request, num);
++#endif /* HAVE_LIBRCC */
++
+ ftp_connect (current_wdata, current_wdata->request, 1);
+ }
+
+@@ -1270,6 +1379,8 @@
+ {
+ GtkWidget *window, *ui;
+
++ rccPatchInit();
++
+ /* We override the read color functions because we are using a GdkColor
+ structures to store the color. If I put this in lib/config_file.c, then
+ the core library would be dependant on Gtk+ being present */
+@@ -1336,6 +1447,8 @@
+ GDK_THREADS_ENTER ();
+ gtk_main ();
+ GDK_THREADS_LEAVE ();
++
++ rccPatchFree();
+
+ return (0);
+ }
diff --git a/patches/gstreamer/gst-plugins-good-0.10.16-rusxmms.diff b/patches/gstreamer/gst-plugins-good-0.10.16-rusxmms.diff
new file mode 100644
index 0000000..95aea19
--- /dev/null
+++ b/patches/gstreamer/gst-plugins-good-0.10.16-rusxmms.diff
@@ -0,0 +1,224 @@
+diff -dPNur gst-plugins-good-0.10.16/configure.ac gst-plugins-good-0.10.16-ds/configure.ac
+--- gst-plugins-good-0.10.16/configure.ac 2009-08-29 00:05:24.000000000 +0400
++++ gst-plugins-good-0.10.16-ds/configure.ac 2009-10-29 06:20:29.000000000 +0300
+@@ -939,6 +939,13 @@
+ AC_SUBST(BZ2_LIBS)
+ ])
+
++dnl *** id3demux to use LibRCC
++translit(dnm, m, l) AM_CONDITIONAL(USE_LIBRCC, true)
++AG_GST_CHECK_FEATURE(LIBRCC, [librcc support for id3demux],, [
++ AG_GST_CHECK_LIBHEADER(LIBRCC, rcc, rccInit, ,librcc.h, LIBRCC_LIBS="-lrcc")
++ AC_SUBST(LIBRCC_LIBS)
++])
++
+ else
+
+ dnl not building plugins with external dependencies,
+@@ -974,6 +981,7 @@
+ AM_CONDITIONAL(USE_XSHM, false)
+ AM_CONDITIONAL(USE_XVIDEO, false)
+ AM_CONDITIONAL(USE_ZLIB, false)
++AM_CONDITIONAL(USE_LIBRCC, false)
+
+ fi dnl of EXT plugins
+
+diff -dPNur gst-plugins-good-0.10.16/gst/id3demux/gstid3demux.c gst-plugins-good-0.10.16-ds/gst/id3demux/gstid3demux.c
+--- gst-plugins-good-0.10.16/gst/id3demux/gstid3demux.c 2009-08-11 02:15:55.000000000 +0400
++++ gst-plugins-good-0.10.16-ds/gst/id3demux/gstid3demux.c 2009-10-29 06:44:25.000000000 +0300
+@@ -56,6 +56,7 @@
+
+ #include "gstid3demux.h"
+ #include "id3tags.h"
++#include "rccpatch.h"
+
+ static const GstElementDetails gst_id3demux_details =
+ GST_ELEMENT_DETAILS ("ID3 tag demuxer",
+@@ -107,11 +108,22 @@
+ }
+
+ static void
++gst_id3demux_finalize (GObject * object)
++{
++ GstID3Demux *demux = GST_ID3DEMUX (object);
++
++ rcc_patch_unref();
++
++ G_OBJECT_CLASS (parent_class)->finalize (object);
++}
++
++static void
+ gst_id3demux_class_init (GstID3DemuxClass * klass)
+ {
+ GstTagDemuxClass *tagdemux_class = (GstTagDemuxClass *) klass;
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
++ gobject_class->finalize = gst_id3demux_finalize;
+ gobject_class->set_property = gst_id3demux_set_property;
+ gobject_class->get_property = gst_id3demux_get_property;
+
+@@ -133,6 +145,7 @@
+ gst_id3demux_init (GstID3Demux * id3demux, GstID3DemuxClass * klass)
+ {
+ id3demux->prefer_v1 = DEFAULT_PREFER_V1;
++ rcc_patch_ref();
+ }
+
+ static gboolean
+diff -dPNur gst-plugins-good-0.10.16/gst/id3demux/id3v2frames.c gst-plugins-good-0.10.16-ds/gst/id3demux/id3v2frames.c
+--- gst-plugins-good-0.10.16/gst/id3demux/id3v2frames.c 2009-08-11 02:15:55.000000000 +0400
++++ gst-plugins-good-0.10.16-ds/gst/id3demux/id3v2frames.c 2009-10-29 06:40:17.000000000 +0300
+@@ -33,6 +33,7 @@
+ #endif
+
+ #include "id3tags.h"
++#include "rccpatch.h"
+
+ GST_DEBUG_CATEGORY_EXTERN (id3demux_debug);
+ #define GST_CAT_DEFAULT (id3demux_debug)
+@@ -986,7 +987,12 @@
+ utf8 = NULL;
+ }
+ }
+- }
++ }
++
++ /* Try LibRCC library to detect encoding */
++ utf8 = rcc_patch_to_utf8(start, size);
++ if (utf8) goto beach;
++
+ /* Try current locale (if not UTF-8) */
+ if (!g_get_charset (&env)) {
+ if ((utf8 = g_locale_to_utf8 (start, size, &bytes_read, NULL, NULL))) {
+diff -dPNur gst-plugins-good-0.10.16/gst/id3demux/Makefile.am gst-plugins-good-0.10.16-ds/gst/id3demux/Makefile.am
+--- gst-plugins-good-0.10.16/gst/id3demux/Makefile.am 2009-08-11 02:15:55.000000000 +0400
++++ gst-plugins-good-0.10.16-ds/gst/id3demux/Makefile.am 2009-10-29 06:20:06.000000000 +0300
+@@ -1,10 +1,15 @@
+ plugin_LTLIBRARIES = libgstid3demux.la
+
+-libgstid3demux_la_SOURCES = gstid3demux.c id3tags.c id3v2frames.c
++libgstid3demux_la_SOURCES = gstid3demux.c id3tags.c id3v2frames.c rccpatch.c
+ libgstid3demux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+ libgstid3demux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_MAJORMINOR@ \
+ -lgstpbutils-@GST_MAJORMINOR@ $(GST_BASE_LIBS) $(ZLIB_LIBS)
+ libgstid3demux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+ libgstid3demux_la_LIBTOOLFLAGS = --tag=disable-static
+
+-noinst_HEADERS = gstid3demux.h id3tags.h
++if USE_LIBRCC
++ libgstid3demux_la_LIBADD += @LIBRCC_LIBS@
++endif
++
++
++noinst_HEADERS = gstid3demux.h id3tags.h rccpatch.h
+diff -dPNur gst-plugins-good-0.10.16/gst/id3demux/rccpatch.c gst-plugins-good-0.10.16-ds/gst/id3demux/rccpatch.c
+--- gst-plugins-good-0.10.16/gst/id3demux/rccpatch.c 1970-01-01 03:00:00.000000000 +0300
++++ gst-plugins-good-0.10.16-ds/gst/id3demux/rccpatch.c 2009-10-29 07:05:20.000000000 +0300
+@@ -0,0 +1,91 @@
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <stdlib.h>
++#include "rccpatch.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 */
++
++
++static void rcc_patch_free() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) {
++ puts("clean");
++ rccFree();
++ rcc_initialized = 0;
++ }
++#endif /* HAVE_LIBRCC */
++}
++
++static void rcc_patch_init() {
++#ifdef HAVE_LIBRCC
++ if (rcc_initialized) return;
++ puts("init");
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++#endif /* HAVE_LIBRCC */
++}
++
++static int registered = 0;
++static int ref_count = 0;
++static GStaticMutex lock = G_STATIC_MUTEX_INIT;
++
++void rcc_patch_ref() {
++ puts("ref");
++ g_static_mutex_lock(&lock);
++ if (!registered) {
++ g_atexit(rcc_patch_free);
++ registered = 1;
++ }
++ if (++ref_count==1) rcc_patch_init();
++ g_static_mutex_unlock(&lock);
++}
++
++void rcc_patch_unref() {
++ puts("unref");
++ g_static_mutex_lock(&lock);
++ if (--ref_count==0) rcc_patch_free();
++ g_static_mutex_unlock(&lock);
++}
++
++gchar *rcc_patch_to_utf8(const gchar *str, const guint size) {
++#ifdef HAVE_LIBRCC
++ gchar *res;
++
++ if (rcc_initialized) {
++ g_static_mutex_lock(&lock);
++ res = rccSizedRecode(ctx, ID3_CLASS, UTF_CLASS, str, size, NULL);
++ g_static_mutex_unlock(&lock);
++
++ return res;
++ }
++#endif /* HAVE_LIBRCC */
++
++ return NULL;
++}
++
+diff -dPNur gst-plugins-good-0.10.16/gst/id3demux/rccpatch.h gst-plugins-good-0.10.16-ds/gst/id3demux/rccpatch.h
+--- gst-plugins-good-0.10.16/gst/id3demux/rccpatch.h 1970-01-01 03:00:00.000000000 +0300
++++ gst-plugins-good-0.10.16-ds/gst/id3demux/rccpatch.h 2009-10-29 06:23:58.000000000 +0300
+@@ -0,0 +1,12 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include <gst/gst.h>
++
++void rcc_patch_ref();
++void rcc_patch_unref();
++
++gchar *rcc_patch_to_utf8(const gchar *str, const guint size);
++
++
++#endif /* _RCC_PATCH_H */
diff --git a/patches/gstreamer/gstreamer b/patches/gstreamer/gstreamer
new file mode 100644
index 0000000..86a0b5f
--- /dev/null
+++ b/patches/gstreamer/gstreamer
@@ -0,0 +1,14 @@
+totem -> gstreamer ->
+ mp3 playback [mad,ffmpeg,flump3dec]
+ id3 id3demux (plugins-good)
+ it uses tag functions (from plugins-base/gst-libs/gst/tag) to
+ access id3 v.1 and maintains id3 v.2 itself.
+
+tag contains 'gst_tag_freeform_string_to_utf8' which should be rcc'ized and
+used from id3demux (and probably other places) instead of current patch.
+
+The question is initialization...
+
+
+GST_TAG_ENCODING=CP1251 totem 01_-_vpotmah_192_lame_cbr.mp3
+
diff --git a/patches/gstreamer/libid3_problems b/patches/gstreamer/libid3_problems
new file mode 100644
index 0000000..4d74a7f
--- /dev/null
+++ b/patches/gstreamer/libid3_problems
@@ -0,0 +1,3 @@
+problems with building of libid3 complaining due to id3_frametype_* undefined are due to
+ - missing gperf and as a result empty frametype.c and compat.c generated
+ - gperf should be installed and empty frametype.c, compat.c deleted
diff --git a/patches/id3lib/id3lib-ds-rcc.patch b/patches/id3lib/id3lib-ds-rcc.patch
new file mode 100644
index 0000000..22c7aa9
--- /dev/null
+++ b/patches/id3lib/id3lib-ds-rcc.patch
@@ -0,0 +1,169 @@
+diff -dPNur id3lib-3.8.3-orig/configure.in id3lib-3.8.3-new/configure.in
+--- id3lib-3.8.3-orig/configure.in 2003-03-02 01:23:00.000000000 +0100
++++ id3lib-3.8.3-new/configure.in 2005-07-19 22:03:12.000000000 +0200
+@@ -217,6 +217,20 @@
+ LIBS="$LIBS $ICONV_LIB"
+ fi
+
++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 Check for c++ features
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+@@ -315,5 +329,5 @@
+ src/Makefile \
+ examples/Makefile \
+ prj/Makefile \
+- libprj/Makefile
++ libprj/Makefile
+ )
+diff -dPNur id3lib-3.8.3-orig/src/field_string_ascii.cpp id3lib-3.8.3-new/src/field_string_ascii.cpp
+--- id3lib-3.8.3-orig/src/field_string_ascii.cpp 2003-03-02 01:23:00.000000000 +0100
++++ id3lib-3.8.3-new/src/field_string_ascii.cpp 2005-07-19 21:34:12.000000000 +0200
+@@ -27,6 +27,7 @@
+ #include "field_impl.h"
+ #include "id3/utils.h" // has <config.h> "id3/id3lib_streams.h" "id3/globals.h" "id3/id3lib_strings.h"
+ #include "io_helpers.h"
++#include "rccpatch.h"
+
+ using namespace dami;
+
+@@ -92,8 +93,15 @@
+ buffer != NULL && maxLength > 0)
+ {
+ String data = this->GetText();
++ char *recoded = rccPatchRecode(data.data(), (size_t)data.size(), (size_t*)&size);
++ if (recoded) {
++ size = dami::min(maxLength, size);
++ ::memcpy(buffer, recoded, size);
++ free(recoded);
++ } else {
+ size = dami::min(maxLength, data.size());
+ ::memcpy(buffer, data.data(), size);
++ }
+ if (size < maxLength)
+ {
+ buffer[size] = '\0';
+diff -dPNur id3lib-3.8.3-orig/src/Makefile.am id3lib-3.8.3-new/src/Makefile.am
+--- id3lib-3.8.3-orig/src/Makefile.am 2003-03-02 01:23:00.000000000 +0100
++++ id3lib-3.8.3-new/src/Makefile.am 2005-07-19 21:38:31.000000000 +0200
+@@ -17,7 +17,7 @@
+ zlib_include =
+ endif
+
+-INCLUDES = \
++INCLUDES = @LIBRCC_INCLUDES@ \
+ @ID3LIB_DEBUG_FLAGS@ -I$(top_srcdir)/include/id3 -I$(top_srcdir)/include $(zlib_include)
+
+ noinst_HEADERS = \
+@@ -31,7 +31,8 @@
+ header_tag.h \
+ mp3_header.h \
+ tag_impl.h \
+- spec.h
++ spec.h \
++ rccpatch.h
+
+ id3lib_sources = \
+ c_wrapper.cpp \
+@@ -66,7 +67,8 @@
+ tag_parse_v1.cpp \
+ tag_render.cpp \
+ utils.cpp \
+- writers.cpp
++ writers.cpp \
++ rccpatch.cpp
+
+ lib_LTLIBRARIES = libid3.la
+
+@@ -77,6 +79,7 @@
+ endif
+
+ libid3_la_LDFLAGS = \
++ @LIBRCC_LIBS@ \
+ -version-info $(LT_VERSION) \
+ -release $(LT_RELEASE) \
+ -export-dynamic
+diff -dPNur id3lib-3.8.3-orig/src/rccpatch.cpp id3lib-3.8.3-new/src/rccpatch.cpp
+--- id3lib-3.8.3-orig/src/rccpatch.cpp 1970-01-01 01:00:00.000000000 +0100
++++ id3lib-3.8.3-new/src/rccpatch.cpp 2005-07-19 22:10:47.000000000 +0200
+@@ -0,0 +1,60 @@
++#include <stdlib.h>
++
++#include "../config.h"
++
++#ifdef HAVE_LIBRCC
++# include <librcc.h>
++#endif /* HAVE_LIBRCC */
++
++
++#ifdef HAVE_LIBRCC
++# define ID3_CLASS 0
++# define OUT_CLASS 1
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, NULL, NULL, "Output Encoding", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int rcc_initialized = 0;
++#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 */
++}
++
++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
++ char *res;
++ rccPatchTryInit();
++ return rccSizedRecode(NULL, ID3_CLASS, OUT_CLASS, str, len, rlen);
++#else
++ return NULL;
++#endif /* HAVE_LIBRCC */
++}
+diff -dPNur id3lib-3.8.3-orig/src/rccpatch.h id3lib-3.8.3-new/src/rccpatch.h
+--- id3lib-3.8.3-orig/src/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ id3lib-3.8.3-new/src/rccpatch.h 2005-07-19 21:34:51.000000000 +0200
+@@ -0,0 +1,3 @@
++void rccPatchFree();
++void rccPatchInit();
++char *rccPatchRecode(const char *str, size_t len, size_t *rlen);
diff --git a/patches/libid3tag/README b/patches/libid3tag/README
new file mode 100644
index 0000000..f927e0d
--- /dev/null
+++ b/patches/libid3tag/README
@@ -0,0 +1,2 @@
+Read-only patch. The configuration in 'xmms' config. Both ID3 ID3 v.2 Latin1
+encoding is taken out of 'id3' class.
diff --git a/patches/libid3tag/libid3tag-0.15.1b-ds-rcc.patch b/patches/libid3tag/libid3tag-0.15.1b-ds-rcc.patch
new file mode 100644
index 0000000..4641f3d
--- /dev/null
+++ b/patches/libid3tag/libid3tag-0.15.1b-ds-rcc.patch
@@ -0,0 +1,300 @@
+diff -dPNur libid3tag-0.15.1b/configure.ac libid3tag-0.15.1b-ds/configure.ac
+--- libid3tag-0.15.1b/configure.ac 2004-01-24 00:22:46.000000000 +0100
++++ libid3tag-0.15.1b-ds/configure.ac 2008-04-12 21:36:35.000000000 +0200
+@@ -145,6 +145,22 @@
+ *** environment variable to specify its installed location, e.g. -L<dir>.])
+ ])
+
++
++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 handle --enable and --disable options
+
+ AC_CACHE_SAVE
+diff -dPNur libid3tag-0.15.1b/latin1.c libid3tag-0.15.1b-ds/latin1.c
+--- libid3tag-0.15.1b/latin1.c 2004-01-23 10:41:32.000000000 +0100
++++ libid3tag-0.15.1b-ds/latin1.c 2008-04-12 21:36:35.000000000 +0200
+@@ -31,6 +31,9 @@
+ # include "latin1.h"
+ # include "ucs4.h"
+
++# include "utf8.h"
++# include "rccpatch.h"
++
+ /*
+ * NAME: latin1->length()
+ * DESCRIPTION: return the number of ucs4 chars represented by a latin1 string
+@@ -172,6 +175,11 @@
+ id3_length_t size = 0;
+ id3_latin1_t latin1[1], *out;
+
++/*
++ Theoretically, we should add here a code for converting ucs4 to
++ recoded latin1 string. However, using non-standard latin1 tags
++ in ID3v.2 tags is completely idiotic. So, I'll not do that.
++*/
+ while (*ucs4) {
+ switch (id3_latin1_encodechar(out = latin1, *ucs4++)) {
+ case 1: size += id3_latin1_put(ptr, *out++);
+@@ -193,6 +201,7 @@
+ {
+ id3_byte_t const *end;
+ id3_latin1_t *latin1ptr, *latin1;
++ id3_utf8_t *utf8;
+ id3_ucs4_t *ucs4;
+
+ end = *ptr + length;
+@@ -207,6 +216,19 @@
+
+ *latin1ptr = 0;
+
++
++ utf8 = rccPatchLatin2UTF(latin1);
++ if (utf8) {
++ ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4));
++ if (ucs4)
++ id3_utf8_decode(utf8, ucs4);
++ free(utf8);
++ free(latin1);
++
++
++ return ucs4;
++ }
++
+ ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4));
+ if (ucs4)
+ id3_latin1_decode(latin1, ucs4);
+diff -dPNur libid3tag-0.15.1b/Makefile.am libid3tag-0.15.1b-ds/Makefile.am
+--- libid3tag-0.15.1b/Makefile.am 2004-02-17 03:11:28.000000000 +0100
++++ libid3tag-0.15.1b-ds/Makefile.am 2008-04-12 21:36:35.000000000 +0200
+@@ -81,6 +81,7 @@
+ libid3tag_la_SOURCES = version.c ucs4.c latin1.c utf16.c utf8.c \
+ parse.c render.c field.c frametype.c compat.c \
+ genre.c frame.c crc.c util.c tag.c file.c \
++ rccpatch.c rccpatch.h \
+ version.h ucs4.h latin1.h utf16.h utf8.h \
+ parse.h render.h field.h frametype.h compat.h \
+ genre.h frame.h crc.h util.h tag.h file.h \
+@@ -90,7 +91,8 @@
+ frametype.gperf compat.gperf genre.dat.in \
+ debug.c debug.h
+
+-libid3tag_la_LDFLAGS = -version-info $(version_info)
++INCLUDES = @LIBRCC_INCLUDES@
++libid3tag_la_LDFLAGS = -version-info $(version_info) @LIBRCC_LIBS@
+
+ BUILT_SOURCES = frametype.c compat.c genre.dat
+
+diff -dPNur libid3tag-0.15.1b/rccpatch.c libid3tag-0.15.1b-ds/rccpatch.c
+--- libid3tag-0.15.1b/rccpatch.c 1970-01-01 01:00:00.000000000 +0100
++++ libid3tag-0.15.1b-ds/rccpatch.c 2008-04-12 21:36:35.000000000 +0200
+@@ -0,0 +1,96 @@
++#include <stdlib.h>
++#include "rccpatch.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 */
++}
++
++
++id3_utf8_t *rccPatchLatin2UTF(id3_latin1_t *str) {
++#ifdef HAVE_LIBRCC
++ rccPatchTryInit();
++
++ return rccRecode(ctx, ID3_CLASS, UTF_CLASS, str);
++#else
++ return NULL;
++#endif /* HAVE_LIBRCC */
++}
++
++id3_latin1_t *rccPatchUTF2Latin(id3_utf8_t *str) {
++#ifdef HAVE_LIBRCC
++ rccPatchTryInit();
++
++ return rccRecode(ctx, UTF_CLASS, ID3_CLASS, str);
++#else
++ return NULL;
++#endif /* HAVE_LIBRCC */
++}
++
++id3_latin1_t *rccPatchUTF2Out(id3_utf8_t *str) {
++#ifdef HAVE_LIBRCC
++ rccPatchTryInit();
++
++ return rccRecode(ctx, UTF_CLASS, OUT_CLASS, str);
++#else
++ return NULL;
++#endif /* HAVE_LIBRCC */
++}
++
+diff -dPNur libid3tag-0.15.1b/rccpatch.h libid3tag-0.15.1b-ds/rccpatch.h
+--- libid3tag-0.15.1b/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ libid3tag-0.15.1b-ds/rccpatch.h 2008-04-12 21:36:35.000000000 +0200
+@@ -0,0 +1,15 @@
++#ifndef _RCC_PATCH_H
++#define _RCC_PATCH_H
++
++#include "id3tag.h"
++
++void rccPatchFree();
++void rccPatchInit();
++void rccPatchSetContext(void *newctx);
++
++id3_utf8_t *rccPatchLatin2UTF(id3_latin1_t *str);
++id3_latin1_t *rccPatchUTF2Latin(id3_utf8_t *str);
++id3_latin1_t *rccPatchUTF2Out(id3_utf8_t *str);
++
++
++#endif /* _RCC_PATCH_H */
+diff -dPNur libid3tag-0.15.1b/tag.c libid3tag-0.15.1b-ds/tag.c
+--- libid3tag-0.15.1b/tag.c 2004-02-17 03:04:10.000000000 +0100
++++ libid3tag-0.15.1b-ds/tag.c 2008-04-12 21:37:12.000000000 +0200
+@@ -45,6 +45,9 @@
+ # include "field.h"
+ # include "util.h"
+
++# include "utf8.h"
++# include "rccpatch.h"
++
+ /*
+ * NAME: tag->new()
+ * DESCRIPTION: allocate and return a new, empty tag
+@@ -335,6 +338,8 @@
+ {
+ struct id3_frame *frame;
+ id3_ucs4_t ucs4[31];
++
++ id3_utf8_t *utf8;
+
+ if (text) {
+ trim(text);
+@@ -350,9 +355,15 @@
+ ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1)
+ goto fail;
+
+- if (text)
++ if (text) {
++ utf8 = rccPatchLatin2UTF(text);
++ if (utf8) {
++ if (strlen(utf8) > 30) utf8[30] = 0;
++ id3_utf8_decode(utf8, ucs4);
++ free(utf8);
++ } else
+ id3_latin1_decode(text, ucs4);
+- else
++ } else
+ id3_ucs4_putnumber(ucs4, number);
+
+ if (strcmp(id, ID3_FRAME_COMMENT) == 0) {
+diff -dPNur libid3tag-0.15.1b/ucs4.c libid3tag-0.15.1b-ds/ucs4.c
+--- libid3tag-0.15.1b/ucs4.c 2004-01-23 10:41:32.000000000 +0100
++++ libid3tag-0.15.1b-ds/ucs4.c 2008-04-12 21:36:35.000000000 +0200
+@@ -33,6 +33,9 @@
+ # include "utf16.h"
+ # include "utf8.h"
+
++# include <string.h>
++# include "rccpatch.h"
++
+ id3_ucs4_t const id3_ucs4_empty[] = { 0 };
+
+ /*
+@@ -125,6 +128,27 @@
+ {
+ id3_latin1_t *latin1;
+
++
++ id3_latin1_t *ltmp;
++ id3_utf8_t *utf8;
++
++ utf8 = malloc(id3_ucs4_utf8size(ucs4) * sizeof(*utf8));
++ if (utf8) {
++ id3_utf8_encode(utf8, ucs4);
++ ltmp = rccPatchUTF2Out(utf8);
++ free(utf8);
++
++ if (ltmp) {
++ latin1 = malloc((1+strlen(ltmp))*sizeof(char));
++ if (latin1) {
++ memcpy(latin1, ltmp, (1+strlen(ltmp)));
++ free(ltmp);
++ return release(latin1);
++ }
++ free(ltmp);
++ }
++ }
++
+ latin1 = malloc(id3_ucs4_latin1size(ucs4) * sizeof(*latin1));
+ if (latin1)
+ id3_latin1_encode(latin1, ucs4);
diff --git a/patches/libtranslate/README.txt b/patches/libtranslate/README.txt
new file mode 100644
index 0000000..e152812
--- /dev/null
+++ b/patches/libtranslate/README.txt
@@ -0,0 +1,5 @@
+Apply the patches in the order they listed. Use patches from 'soup22' directory
+to build against libsoup versions before 2.4, otherwise use patches from
+'soup24' (tested up to 2.8).
+
+Replace data/services.xml.in by provided services.xml with updated services.
diff --git a/patches/libtranslate/libtranslate-ds2-memory.patch b/patches/libtranslate/libtranslate-ds2-memory.patch
new file mode 100644
index 0000000..e05c7b4
--- /dev/null
+++ b/patches/libtranslate/libtranslate-ds2-memory.patch
@@ -0,0 +1,12 @@
+diff -dPNur libtranslate-0.99/src/translate-util.c libtranslate-0.99-new/src/translate-util.c
+--- libtranslate-0.99/src/translate-util.c 2005-01-17 16:45:45.000000000 +0000
++++ libtranslate-0.99-new/src/translate-util.c 2005-12-29 18:35:04.000000000 +0000
+@@ -136,7 +136,7 @@
+ g_return_val_if_fail(big != NULL, NULL);
+ g_return_val_if_fail(little != NULL, NULL);
+
+- lower_big = g_ascii_strdown(big, big_len);
++ lower_big = g_ascii_strdown(big, (int)big_len);
+ lower_little = g_ascii_strdown(little, -1);
+
+ s = strstr(lower_big, lower_little);
diff --git a/patches/libtranslate/libtranslate-ds3-charsetparse.patch b/patches/libtranslate/libtranslate-ds3-charsetparse.patch
new file mode 100644
index 0000000..2f578e9
--- /dev/null
+++ b/patches/libtranslate/libtranslate-ds3-charsetparse.patch
@@ -0,0 +1,47 @@
+--- libtranslate-0.99/src/modules/translate-generic-service.c.orig Mon Apr 11 23:08:47 2005
++++ libtranslate-0.99/src/modules/translate-generic-service.c Mon Apr 11 23:15:54 2005
+@@ -484,7 +484,7 @@
+
+ if (SOUP_STATUS_IS_SUCCESSFUL(message->status_code))
+ {
+- const char *charset = NULL;
++ char *charset = NULL;
+
+ if (flags & TRANSFER_CONVERT)
+ {
+@@ -493,14 +493,31 @@
+ content_type = translate_generic_service_get_header(message, &info, "Content-Type");
+ if (content_type)
+ {
+- charset = translate_ascii_strcasestr(content_type, "charset=");
+- if (charset)
+- charset += 8;
++ const char *tmp;
++
++ tmp = translate_ascii_strcasestr(content_type, "charset=");
++ if (tmp)
++ {
++ int len;
++
++ tmp += 8;
++ if (*tmp == '\'' || *tmp == '"')
++ tmp++;
++
++ len = strlen(tmp);
++ if (len > 0 && (tmp[len - 1] == '\'' || tmp[len - 1] == '"'))
++ len--;
++
++ charset = g_strndup(tmp, len);
++ }
+ }
+ }
+
+ if (charset)
+- response = g_convert(message->response.body, message->response.length, "UTF-8", charset, NULL, NULL, err);
++ {
++ response = g_convert(message->response.body, message->response.length, "UTF-8", charset, NULL, NULL, err);
++ g_free(charset);
++ }
+ else
+ {
+ if ((flags & TRANSFER_CONVERT) && ! g_utf8_validate(message->response.body, message->response.length, NULL))
diff --git a/patches/libtranslate/libtranslate-ds4-condfix.patch b/patches/libtranslate/libtranslate-ds4-condfix.patch
new file mode 100644
index 0000000..9915a80
--- /dev/null
+++ b/patches/libtranslate/libtranslate-ds4-condfix.patch
@@ -0,0 +1,38 @@
+--- libtranslate-0.99/src/translate-session.c.orig Mon Apr 11 22:44:53 2005
++++ libtranslate-0.99/src/translate-session.c Mon Apr 11 22:51:48 2005
+@@ -703,7 +703,14 @@
+ GError *tmp_err = NULL;
+
+ g_mutex_lock(info->mutex);
+- ret = info->err != NULL;
++ if (info->err)
++ {
++ ret = TRUE;
++ if (info->progress_cond)
++ g_cond_signal(info->progress_cond);
++ }
++ else
++ ret = FALSE;
+ g_mutex_unlock(info->mutex);
+
+ if (ret)
+@@ -728,6 +735,9 @@
+ else
+ g_propagate_error(&info->err, tmp_err);
+
++ if (info->progress_cond)
++ g_cond_signal(info->progress_cond);
++
+ g_mutex_unlock(info->mutex);
+
+ return;
+@@ -759,6 +769,9 @@
+ info->err = g_error_new(TRANSLATE_SESSION_ERROR,
+ TRANSLATE_SESSION_ERROR_NO_SERVICE,
+ _("no service could translate chunk"));
++
++ if (info->progress_cond)
++ g_cond_signal(info->progress_cond);
+ }
+
+ g_mutex_unlock(info->mutex);
diff --git a/patches/libtranslate/libtranslate-ds5-empty.patch b/patches/libtranslate/libtranslate-ds5-empty.patch
new file mode 100644
index 0000000..eb2e0ce
--- /dev/null
+++ b/patches/libtranslate/libtranslate-ds5-empty.patch
@@ -0,0 +1,17 @@
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-service.c libtranslate-0.99-new/src/modules/translate-generic-service.c
+--- libtranslate-0.99/src/modules/translate-generic-service.c 2007-06-27 17:26:10.000000000 +0200
++++ libtranslate-0.99-new/src/modules/translate-generic-service.c 2007-06-27 17:23:55.000000000 +0200
+@@ -1042,6 +1042,13 @@
+
+ g_free(response);
+ }
++
++ if ((!answer)&&(!*err)) {
++ g_set_error(err,
++ TRANSLATE_GENERIC_SERVICE_ERROR,
++ TRANSLATE_GENERIC_SERVICE_ERROR_PARSE,
++ _("empty server response"));
++ }
+
+ return answer ? g_string_free(answer, FALSE) : NULL;
+ }
diff --git a/patches/libtranslate/libtranslate-ds6-promt.patch b/patches/libtranslate/libtranslate-ds6-promt.patch
new file mode 100644
index 0000000..6b30145
--- /dev/null
+++ b/patches/libtranslate/libtranslate-ds6-promt.patch
@@ -0,0 +1,27 @@
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-service.c libtranslate-0.99-new/src/modules/translate-generic-service.c
+--- libtranslate-0.99/src/modules/translate-generic-service.c 2007-06-27 17:26:10.000000000 +0200
++++ libtranslate-0.99-new/src/modules/translate-generic-service.c 2007-06-27 17:23:55.000000000 +0200
+@@ -1238,7 +1245,22 @@
+ {
+ if (modifier_value)
+ g_warning(_("%s: value specified for \"escape\" modifier"), warning_prefix);
+- modified = soup_uri_encode(value, NULL);
++ modified = soup_uri_encode(value, "&");
++ }
++ else if (! strcmp(modifier_name, "entities"))
++ {
++ int i;
++ char *ptr;
++
++ modified = g_malloc(strlen(value)*6 + 1);
++ for (i=0,ptr=modified;value[i];i++) {
++ if ((unsigned char)(value[i])<160) *(ptr++)=value[i];
++ else {
++ sprintf(ptr, "&#%u;", (unsigned char)(value[i]));
++ ptr+=6;
++ }
++ }
++ *ptr = 0;
+ }
+ else if (! strcmp(modifier_name, "charset"))
+ {
diff --git a/patches/libtranslate/libtranslate-ds7-fixcharset.patch b/patches/libtranslate/libtranslate-ds7-fixcharset.patch
new file mode 100644
index 0000000..0665d2f
--- /dev/null
+++ b/patches/libtranslate/libtranslate-ds7-fixcharset.patch
@@ -0,0 +1,93 @@
+diff -dPNur libtranslate-0.99-new/src/modules/translate-generic-parser.c libtranslate-0.99-new-uk/src/modules/translate-generic-parser.c
+--- libtranslate-0.99-new/src/modules/translate-generic-parser.c 2005-01-17 17:46:24.000000000 +0100
++++ libtranslate-0.99-new-uk/src/modules/translate-generic-parser.c 2007-06-27 22:40:04.000000000 +0200
+@@ -726,6 +726,7 @@
+ {
+ const char *url;
+ const char *post;
++ const char *charset;
+ const char *content_type;
+
+ g_return_if_fail(info != NULL);
+@@ -740,6 +741,7 @@
+ "url", REQUIRED, &url,
+ "post", OPTIONAL, &post,
+ "content-type", OPTIONAL, &content_type,
++ "response-charset", OPTIONAL, &charset,
+ NULL);
+
+ if (! *err)
+@@ -748,6 +750,7 @@
+ (*location)->url = g_strdup(url);
+ (*location)->post = g_strdup(post);
+ (*location)->content_type = g_strdup(content_type ? content_type : "application/x-www-form-urlencoded");
++ (*location)->response_charset = g_strdup(charset);
+ }
+ }
+
+@@ -759,6 +762,7 @@
+ g_free(location->url);
+ g_free(location->post);
+ g_free(location->content_type);
++ g_free(location->response_charset);
+ g_slist_foreach(location->http_headers, (GFunc) translate_generic_http_header_free, NULL);
+ g_slist_free(location->http_headers);
+ g_free(location);
+diff -dPNur libtranslate-0.99-new/src/modules/translate-generic-parser.h libtranslate-0.99-new-uk/src/modules/translate-generic-parser.h
+--- libtranslate-0.99-new/src/modules/translate-generic-parser.h 2005-01-17 17:46:30.000000000 +0100
++++ libtranslate-0.99-new-uk/src/modules/translate-generic-parser.h 2007-06-27 22:34:13.000000000 +0200
+@@ -51,6 +51,7 @@
+ char *url;
+ char *post;
+ char *content_type;
++ char *response_charset;
+ GSList *http_headers;
+ } TranslateGenericLocation;
+
+diff -dPNur libtranslate-0.99-new/src/modules/translate-generic-service.c libtranslate-0.99-new-uk/src/modules/translate-generic-service.c
+--- libtranslate-0.99-new/src/modules/translate-generic-service.c 2007-06-27 17:23:55.000000000 +0200
++++ libtranslate-0.99-new-uk/src/modules/translate-generic-service.c 2007-06-27 22:40:29.000000000 +0200
+@@ -129,6 +129,7 @@
+ static char *translate_generic_service_get (const char *uri,
+ const char *post,
+ const char *post_content_type,
++ const char *response_charset,
+ const GSList *headers,
+ TransferFlags flags,
+ GTimeVal *deadline,
+@@ -407,6 +408,7 @@
+ translate_generic_service_get (const char *uri,
+ const char *post,
+ const char *post_content_type,
++ const char *response_charset,
+ const GSList *headers,
+ TransferFlags flags,
+ GTimeVal *deadline,
+@@ -550,9 +552,9 @@
+ }
+ }
+
+- if (charset)
++ if ((charset)||(response_charset))
+ {
+- response = g_convert(message->response.body, message->response.length, "UTF-8", charset, NULL, NULL, err);
++ response = g_convert(message->response.body, message->response.length, "UTF-8", response_charset?response_charset:charset, NULL, NULL, err);
+ g_free(charset);
+ }
+ else
+@@ -941,6 +943,7 @@
+ response = translate_generic_service_get(url,
+ post,
+ group->text_location->content_type,
++ group->text_location->response_charset,
+ headers,
+ TRANSFER_FOLLOW_REFRESH | TRANSFER_CONVERT,
+ deadline,
+@@ -1339,6 +1342,7 @@
+ response = translate_generic_service_get(translation_url,
+ post,
+ group->web_page_location->content_type,
++ group->web_page_location->response_charset,
+ headers,
+ 0,
+ NULL,
diff --git a/patches/libtranslate/services.xml b/patches/libtranslate/services.xml
new file mode 100644
index 0000000..14d0548
--- /dev/null
+++ b/patches/libtranslate/services.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE services SYSTEM "services.dtd">
+<services>
+ <custom-language tag="zh-TW" name="Chinese (Taiwan)"/>
+
+ <service nick="Google" name="google">
+ <group>
+ <language to="*" tag="en"/>
+ <language to="en,de" tag="fr"/>
+ <language to="en,fr" tag="de"/>
+ <language to="en" tag="it"/>
+ <language to="en" tag="pt"/>
+ <language to="en" tag="es"/>
+ <language to="en" tag="pt"/>
+ <language to="en" tag="ru"/>
+ <language to="en" tag="zh"/>
+ <language to="en" tag="zh-TW"/>
+ <language to="en" tag="ja"/>
+ <language to="en" tag="ko"/>
+ <language to="en" tag="ar"/>
+ <text-translation url="http://www.google.com/translate_t?text=${text:escape}&amp;langpair=${from}|${to}&amp;ie=utf8&amp;oe=utf8">
+ <pre-marker text="id=result_box"/>
+ <pre-marker text="mouseover"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;br&gt;"/>
+ </text-translation>
+ <web-page-translation url="http://www.google.com/translate_c?u=${url:escape}&amp;langpair=${from}|${to}"/>
+ </group>
+ </service>
+
+ <service nick="FreeTranslation" name="freetranslation" max-chunk-len="600">
+ <group>
+ <language to="en" tag="nl" service-tag="dutch"/>
+ <language to="*" tag="en" service-tag="english"/>
+ <language to="en" tag="fr" service-tag="french"/>
+ <language to="en" tag="de" service-tag="german"/>
+ <language to="en" tag="it" service-tag="italian"/>
+ <language tag="no" service-tag="norwegian"/>
+ <language to="en" tag="pt" service-tag="portuguese"/>
+ <language to="en" tag="es" service-tag="spanish"/>
+ <text-translation url="http://ets.freetranslation.com/?sequence=core&amp;srctext=${text:escape}&amp;language=${from}/${to}&amp;charset=utf-8"/>
+ <web-page-translation url="http://fets5.freetranslation.com/?sequence=core&amp;url=${url:escape}&amp;language=${from}/${to}"/>
+ </group>
+ <group>
+ <language tag="zh" service-tag="simplifiedchinese"/>
+ <language tag="zh-TW" service-tag="traditionalchinese"/>
+ <language to="*" tag="en" service-tag="english"/>
+ <language to="en" tag="ru" service-tag="russian"/>
+ <text-translation url="http://ets6.freetranslation.com/?sequence=core&amp;srctext=${text:escape}&amp;language=${from}/${to}&amp;charset=utf-8"/>
+ </group>
+ <group>
+ <language to="*" tag="en" service-tag="english"/>
+ <language to="en" tag="ja" service-tag="japanese"/>
+ <text-translation url="http://tets9.freetranslation.com/?sequence=core&amp;srctext=${text:escape}&amp;language=${from}/${to}&amp;charset=utf-8"/>
+ </group>
+ </service>
+
+ <service nick="Pereklad" name="pereklad">
+ <group>
+ <language to="*" tag="ru" service-tag="Rus"/>
+ <language to="*" tag="uk" service-tag="Ukr"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="*" tag="en" service-tag="Eng"/>
+ <language to="*" tag="de" service-tag="Ger"/>
+ <language to="*" tag="fr" service-tag="Fra"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}"
+ response-charset="ISO-8859-1">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="en,de,fr" tag="ru" service-tag="Rus"/>
+ <language to="en,de,fr" tag="uk" service-tag="Ukr"/>
+ <language to="" tag="en" service-tag="Eng"/>
+ <language to="" tag="de" service-tag="Ger"/>
+ <language to="" tag="fr" service-tag="Fra"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}"
+ response-charset="ISO-8859-1">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="" tag="ru" service-tag="Rus"/>
+ <language to="" tag="uk" service-tag="Ukr"/>
+ <language to="ru,uk" tag="en" service-tag="Eng"/>
+ <language to="ru,uk" tag="de" service-tag="Ger"/>
+ <language to="ru,uk" tag="fr" service-tag="Fra"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="" tag="ru" service-tag="Rus"/>
+ <language to="" tag="uk" service-tag="Ukr"/>
+ <language to="ru,uk" tag="lv" service-tag="Lat"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="*" tag="lv" service-tag="Lat"/>
+ <language to="" tag="en" service-tag="Eng"/>
+ <language to="" tag="de" service-tag="Ger"/>
+ <language to="" tag="fr" service-tag="Fra"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}"
+ response-charset="ISO-8859-1">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="" tag="lv" service-tag="Lat"/>
+ <language to="lv" tag="ru" service-tag="Rus"/>
+ <language to="lv" tag="uk" service-tag="Ukr"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}"
+ response-charset="ISO-8859-4">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ <group>
+ <language to="" tag="lv" service-tag="Lat"/>
+ <language to="lv" tag="en" service-tag="Eng"/>
+ <language to="lv" tag="de" service-tag="Ger"/>
+ <language to="lv" tag="fr" service-tag="Fra"/>
+ <text-translation
+ url="http://pereklad.online.ua/"
+ post="TranFrom=${from}&amp;TranTo=${to}&amp;SrcTxt=${text:escape}"
+ response-charset="ISO-8859-4">
+ <pre-marker text="id=&quot;DstTxt&quot;"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea&gt;"/>
+ </text-translation>
+ </group>
+ </service>
+
+ <service nick="Promt" name="promt">
+ <group>
+ <language to="*" tag="ru" service-tag="r"/>
+ <language to="ru,de,fr,es" tag="en" service-tag="e"/>
+ <language to="ru,en,fr,es" tag="de" service-tag="g"/>
+ <language to="ru,en,de,es" tag="fr" service-tag="f"/>
+ <language to="ru,en" tag="it" service-tag="i"/>
+ <language to="ru,en,de,fr" tag="es" service-tag="s"/>
+ <language to="en" tag="pt" service-tag="p"/>
+ <text-translation
+ url="http://www.translate.ru/Default.aspx/Text"
+ post="__EVENTTARGET=&amp;__EVENTTARGUMENT=&amp;ctl00$SiteContent$MA_trasnlform$bTranslate=Translate&amp;ctl00$SiteContent$MA_trasnlform$DropDownList2=&amp;ctl00$SiteContent$trasnlform$sLang=${from}&amp;ctl00$SiteContent$MA_trasnlform$rLang=${to}&amp;ctl00$SiteContent$MA_trasnlform$sourceText=${text:escape}&amp;ctl00$SiteContent$MA_trasnlform$rblTemplates=General">
+ <pre-marker text="ctl00$SiteContent$MA_trasnlform$tbPismo"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/textarea"/>
+
+ </text-translation>
+ </group>
+ </service>
+
+ <service nick="SYSTRAN" name="systran">
+ <group>
+ <language to="en" tag="ar"/>
+ <language to="en" tag="zh"/>
+ <language to="en" tag="zh-TW" service-tag="zt"/>
+ <language to="en,fr" tag="nl"/>
+ <language to="*" tag="en"/>
+ <language to="nl,en,de,it,pt,es" tag="fr"/>
+ <language to="en,fr" tag="de"/>
+ <language to="en,fr" tag="it"/>
+ <language to="en" tag="ja"/>
+ <language to="en" tag="ko"/>
+ <language to="en,fr" tag="pt"/>
+ <language to="en" tag="ru"/>
+ <language to="en,fr" tag="es"/>
+ <language to="en" tag="sv"/>
+ <http-header value="http://www.systransoft.com/" name="Referer"/>
+ <text-translation
+ url="http://www.systranet.com/tt?lp=${from}_${to}&amp;service=translate"
+ post=". ${text}.">
+ <pre-marker text=". "/>
+ <post-marker text="."/>
+ </text-translation>
+ </group>
+ </service>
+
+ <service nick="Babel Fish" name="babelfish">
+ <group>
+ <language to="en" tag="zh"/>
+ <language to="en" tag="zh-TW" service-tag="zt"/>
+ <language to="*" tag="en"/>
+ <language to="en,fr" tag="nl"/>
+ <language to="en,de,el,it,pt,nl,es" tag="fr"/>
+ <language to="en,fr" tag="de"/>
+ <language to="en,fr" tag="el"/>
+ <language to="en,fr" tag="it"/>
+ <language to="en" tag="ja"/>
+ <language to="en" tag="ko"/>
+ <language to="en,fr" tag="pt"/>
+ <language to="en" tag="ru"/>
+ <language to="en,fr" tag="es"/>
+ <text-translation
+ url="http://babelfish.yahoo.com/translate_txt"
+ post="trtext=${text:escape}&amp;lp=${from}_${to}&amp;ei=UTF-8">
+ <pre-marker text="id=&quot;result&quot;"/>
+ <pre-marker text="&lt;div"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&lt;/div"/>
+ </text-translation>
+<!--
+ <web-page-translation url="http://babelfish.altavista.com/babelfish/trurl_load?url=${url:escape}&amp;lp=${from}_${to}&amp;enc=utf8"/>
+!-->
+ </group>
+ </service>
+
+<!--
+ <service nick="Kataku" name="kataku">
+ <group>
+ <language to="*" tag="en"/>
+ <language to="*" tag="id" service-tag="in"/>
+ <text-translation url="http://www.toggletext.com/kataku_trial.php" post="input_text=${text:charset=ISO8859-1,escape}&amp;langset_text=${from}_${to}">
+ <pre-marker text="Translation:"/>
+ <pre-marker text="&lt;pre"/>
+ <pre-marker text="&gt;"/>
+ <post-marker text="&#10;&lt;/pre&gt;"/>
+ </text-translation>
+ <web-page-translation url="http://www.toggletext.com/kataku_webpage_translate.php?input=${url:escape}&amp;langset=${from}_${to}"/>
+ </group>
+ </service>
+-->
+
+</services> \ No newline at end of file
diff --git a/patches/libtranslate/soup22/libtranslate-ds1-timed.patch b/patches/libtranslate/soup22/libtranslate-ds1-timed.patch
new file mode 100644
index 0000000..c98868a
--- /dev/null
+++ b/patches/libtranslate/soup22/libtranslate-ds1-timed.patch
@@ -0,0 +1,352 @@
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-service.c libtranslate-0.99-new/src/modules/translate-generic-service.c
+--- libtranslate-0.99/src/modules/translate-generic-service.c 2005-01-17 17:46:38.000000000 +0100
++++ libtranslate-0.99-new/src/modules/translate-generic-service.c 2005-07-27 22:13:33.000000000 +0200
+@@ -131,6 +131,7 @@
+ const char *post_content_type,
+ const GSList *headers,
+ TransferFlags flags,
++ GTimeVal *deadline,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err);
+@@ -181,6 +182,15 @@
+ gpointer user_data,
+ GError **err);
+
++static char *translate_generic_service_timed_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
++
+ char *translate_generic_service_expand (const char *warning_prefix,
+ const char *str,
+ ...);
+@@ -248,6 +258,7 @@
+
+ service_class->get_pairs = translate_generic_service_get_pairs;
+ service_class->translate_text = translate_generic_service_translate_text;
++ service_class->timed_translate_text = translate_generic_service_timed_translate_text;
+ service_class->translate_web_page = translate_generic_service_translate_web_page;
+
+ g_object_class_install_property(object_class,
+@@ -387,12 +398,18 @@
+ return TRUE; /* continue */
+ }
+
++static void send_message_cb(SoupMessage *req, gpointer user_data) {
++ g_object_ref(req);
++ *(gboolean*)user_data = TRUE;
++}
++
+ static char *
+ translate_generic_service_get (const char *uri,
+ const char *post,
+ const char *post_content_type,
+ const GSList *headers,
+ TransferFlags flags,
++ GTimeVal *deadline,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err)
+@@ -400,6 +417,8 @@
+ TransferInfo info;
+ SoupMessage *message;
+ const GSList *l;
++ GTimeVal tv;
++ gboolean completed = 0, canceled = 0;
+ char *response = NULL;
+
+ g_return_val_if_fail(uri != NULL, FALSE);
+@@ -479,9 +498,27 @@
+ if (translate_generic_debug_flags & TRANSLATE_GENERIC_DEBUG_LOG_TRANSFERS)
+ translate_generic_service_log_connect(message);
+
++ if (deadline) {
++ soup_session_queue_message(info.session, message, send_message_cb, &completed);
++
++ do {
++ g_main_iteration (FALSE);
++ if (completed) break;
++
++ g_get_current_time(&tv);
++ } while ((tv.tv_sec < deadline->tv_sec)||((tv.tv_sec == deadline->tv_sec)&&(tv.tv_usec < deadline->tv_usec)));
++
++ if (!completed) {
++ soup_session_cancel_message(info.session, message);
++ canceled = 1;
++ }
++ } else
+ soup_session_send_message(info.session, message);
+ g_object_unref(info.session);
+
++ if (canceled)
++ g_set_error(err, TRANSLATE_ERROR, TRANSLATE_ERROR_CANCELLED, _("Timeout"));
++ else
+ if (SOUP_STATUS_IS_SUCCESSFUL(message->status_code))
+ {
+ const char *charset = NULL;
+@@ -833,10 +870,11 @@
+ }
+
+ static char *
+-translate_generic_service_translate_text (TranslateService *service,
++translate_generic_service_timed_translate_text (TranslateService *service,
+ const char *text,
+ const char *from,
+ const char *to,
++ GTimeVal *deadline,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err)
+@@ -882,16 +920,16 @@
+
+ headers = g_slist_copy(group->http_headers);
+ headers = g_slist_concat(headers, g_slist_copy(group->text_location->http_headers));
+-
++
+ response = translate_generic_service_get(url,
+ post,
+ group->text_location->content_type,
+ headers,
+ TRANSFER_FOLLOW_REFRESH | TRANSFER_CONVERT,
++ deadline,
+ progress_func,
+ user_data,
+ err);
+-
+ g_free(url);
+ g_free(post);
+ g_slist_free(headers);
+@@ -991,6 +1029,18 @@
+ return answer ? g_string_free(answer, FALSE) : NULL;
+ }
+
++static char *
++translate_generic_service_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err)
++{
++ return translate_generic_service_timed_translate_text(service, text, from, to, NULL, progress_func, user_data, err);
++}
++
+ char *
+ translate_generic_service_expand (const char *warning_prefix,
+ const char *str,
+@@ -1252,6 +1302,7 @@
+ group->web_page_location->content_type,
+ headers,
+ 0,
++ NULL,
+ progress_func,
+ user_data,
+ err);
+@@ -1311,7 +1362,7 @@
+ g_free(proxy_text_uri);
+ }
+
+- session = soup_session_sync_new_with_options(SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
++ session = soup_session_async_new_with_options(SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
+
+ if (proxy_uri)
+ soup_uri_free(proxy_uri);
+diff -dPNur libtranslate-0.99/src/translate-service.c libtranslate-0.99-new/src/translate-service.c
+--- libtranslate-0.99/src/translate-service.c 2005-01-17 17:45:23.000000000 +0100
++++ libtranslate-0.99-new/src/translate-service.c 2005-07-27 17:18:07.000000000 +0200
+@@ -372,6 +372,28 @@
+ }
+
+ char *
++translate_service_timed_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err)
++{
++ g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL);
++ g_return_val_if_fail(TRANSLATE_SERVICE_GET_CLASS(service)->translate_text != NULL, NULL);
++ g_return_val_if_fail(text != NULL, NULL);
++ g_return_val_if_fail(from != NULL, NULL);
++ g_return_val_if_fail(to != NULL, NULL);
++
++ if (TRANSLATE_SERVICE_GET_CLASS(service)->timed_translate_text)
++ return TRANSLATE_SERVICE_GET_CLASS(service)->timed_translate_text(service, text, from, to, deadline, progress_func, user_data, err);
++
++ return TRANSLATE_SERVICE_GET_CLASS(service)->translate_text(service, text, from, to, progress_func, user_data, err);
++}
++
++char *
+ translate_service_translate_web_page (TranslateService *service,
+ const char *url,
+ const char *from,
+diff -dPNur libtranslate-0.99/src/translate-service.h libtranslate-0.99-new/src/translate-service.h
+--- libtranslate-0.99/src/translate-service.h 2005-01-17 17:45:29.000000000 +0100
++++ libtranslate-0.99-new/src/translate-service.h 2005-07-27 16:54:46.000000000 +0200
+@@ -73,6 +73,14 @@
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err);
++ char *(*timed_translate_text)(TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
+ char *(*translate_web_page) (TranslateService *service,
+ const char *url,
+ const char *from,
+diff -dPNur libtranslate-0.99/src/translate-service-private.h libtranslate-0.99-new/src/translate-service-private.h
+--- libtranslate-0.99/src/translate-service-private.h 2005-01-17 17:45:17.000000000 +0100
++++ libtranslate-0.99-new/src/translate-service-private.h 2005-07-27 17:30:00.000000000 +0200
+@@ -41,6 +41,14 @@
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err);
++char *translate_service_timed_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
+ char *translate_service_translate_web_page (TranslateService *service,
+ const char *url,
+ const char *from,
+diff -dPNur libtranslate-0.99/src/translate-session.c libtranslate-0.99-new/src/translate-session.c
+--- libtranslate-0.99/src/translate-session.c 2005-01-17 17:45:35.000000000 +0100
++++ libtranslate-0.99-new/src/translate-session.c 2005-07-27 16:52:46.000000000 +0200
+@@ -62,6 +62,8 @@
+ {
+ GMutex *mutex;
+ GCond *progress_cond;
++
++ GTimeVal *deadline;
+
+ TranslateSession *session;
+ GSList *services;
+@@ -487,6 +489,7 @@
+ * @text: a nul-terminated string.
+ * @from: a RFC 3066 language tag.
+ * @to: a RFC 3066 language tag.
++ * @timeout: timeout in microseconds.
+ * @progress_func: a function to call when progressing, or %NULL.
+ * @user_data: data to pass to @progress_func, or %NULL.
+ * @err: a location to report errors, or %NULL. Any of the errors in
+@@ -505,10 +508,11 @@
+ * when no longer needed.
+ **/
+ char *
+-translate_session_translate_text (TranslateSession *session,
++translate_session_timed_translate_text (TranslateSession *session,
+ const char *text,
+ const char *from,
+ const char *to,
++ gulong timeout,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err)
+@@ -519,6 +523,7 @@
+ unsigned int max_threads;
+ GThreadPool *pool;
+ GSList *l;
++ GTimeVal deadline;
+ unsigned int max_chunk_len = 0;
+ char *translated = NULL;
+
+@@ -527,6 +532,11 @@
+ g_return_val_if_fail(from != NULL, NULL);
+ g_return_val_if_fail(to != NULL, NULL);
+
++ if (timeout) {
++ g_get_current_time(&deadline);
++ g_time_val_add(&deadline, timeout);
++ }
++
+ LOCK(session);
+ info.services = translate_session_get_services_for_translation(session,
+ TRANSLATE_PAIR_TEXT,
+@@ -560,7 +570,8 @@
+ chunks = translate_session_split(text, max_chunk_len);
+
+ info.mutex = g_mutex_new();
+- info.progress_cond = progress_func ? g_cond_new() : NULL;
++ info.progress_cond = (progress_func||timeout) ? g_cond_new() : NULL;
++ info.deadline = timeout ? &deadline : NULL;
+ info.session = session;
+ info.chunks = NULL;
+ info.from = from;
+@@ -614,6 +625,11 @@
+ GSList *l;
+ int n_chunks;
+
++ if (timeout) {
++ if (!g_cond_timed_wait(info.progress_cond, info.mutex, info.deadline))
++ info.err = g_error_new(TRANSLATE_ERROR,TRANSLATE_ERROR_CANCELLED,_("timeout"));
++ break;
++ } else
+ g_cond_wait(info.progress_cond, info.mutex);
+
+ if (info.err)
+@@ -680,6 +696,18 @@
+ return translated;
+ }
+
++char *
++translate_session_translate_text (TranslateSession *session,
++ const char *text,
++ const char *from,
++ const char *to,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err)
++{
++ return translate_session_timed_translate_text(session, text, from, to, 0, progress_func, user_data, err);
++}
++
+ static void
+ translate_session_translate_thread (gpointer data, gpointer user_data)
+ {
+@@ -709,10 +737,11 @@
+ if (ret)
+ return;
+
+- chunk_info->translated = translate_service_translate_text(service,
++ chunk_info->translated = translate_service_timed_translate_text(service,
+ chunk_info->chunk,
+ info->from,
+ info->to,
++ info->deadline,
+ info->progress_cond ? translate_session_translate_progress_cb : NULL,
+ info->progress_cond ? chunk_info : NULL,
+ &tmp_err);
+diff -dPNur libtranslate-0.99/src/translate-session.h libtranslate-0.99-new/src/translate-session.h
+--- libtranslate-0.99/src/translate-session.h 2005-01-17 17:45:40.000000000 +0100
++++ libtranslate-0.99-new/src/translate-session.h 2005-07-27 14:41:05.000000000 +0200
+@@ -93,6 +93,14 @@
+ unsigned int translate_session_get_max_threads (TranslateSession *session);
+ int translate_session_get_max_retries (TranslateSession *session);
+
++char *translate_session_timed_translate_text (TranslateSession *session,
++ const char *text,
++ const char *from,
++ const char *to,
++ gulong timeout,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
+ char *translate_session_translate_text (TranslateSession *session,
+ const char *text,
+ const char *from,
diff --git a/patches/libtranslate/soup24/libtranslate-ds1-timed24.patch b/patches/libtranslate/soup24/libtranslate-ds1-timed24.patch
new file mode 100644
index 0000000..daf3811
--- /dev/null
+++ b/patches/libtranslate/soup24/libtranslate-ds1-timed24.patch
@@ -0,0 +1,360 @@
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-service.c libtranslate-0.99-new/src/modules/translate-generic-service.c
+--- libtranslate-0.99/src/modules/translate-generic-service.c 2005-01-17 17:46:38.000000000 +0100
++++ libtranslate-0.99-new/src/modules/translate-generic-service.c 2005-07-27 22:13:33.000000000 +0200
+@@ -131,6 +131,7 @@
+ const char *post_content_type,
+ const GSList *headers,
+ TransferFlags flags,
++ GTimeVal *deadline,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err);
+@@ -181,6 +182,15 @@
+ gpointer user_data,
+ GError **err);
+
++static char *translate_generic_service_timed_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
++
+ char *translate_generic_service_expand (const char *warning_prefix,
+ const char *str,
+ ...);
+@@ -248,6 +258,7 @@
+
+ service_class->get_pairs = translate_generic_service_get_pairs;
+ service_class->translate_text = translate_generic_service_translate_text;
++ service_class->timed_translate_text = translate_generic_service_timed_translate_text;
+ service_class->translate_web_page = translate_generic_service_translate_web_page;
+
+ g_object_class_install_property(object_class,
+@@ -387,12 +398,22 @@
+ return TRUE; /* continue */
+ }
+
++#ifdef HAVE_LIBSOUP22
++static void send_message_cb(SoupMessage *req, gpointer user_data) {
++#else
++static void send_message_cb(SoupSession *session, SoupMessage *req, gpointer user_data) {
++#endif
++ g_object_ref(req);
++ *(gboolean*)user_data = TRUE;
++}
++
+ static char *
+ translate_generic_service_get (const char *uri,
+ const char *post,
+ const char *post_content_type,
+ const GSList *headers,
+ TransferFlags flags,
++ GTimeVal *deadline,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err)
+@@ -400,6 +417,8 @@
+ TransferInfo info;
+ SoupMessage *message;
+ const GSList *l;
++ GTimeVal tv;
++ gboolean completed = 0, canceled = 0;
+ char *response = NULL;
+
+ g_return_val_if_fail(uri != NULL, FALSE);
+@@ -479,9 +498,31 @@
+ if (translate_generic_debug_flags & TRANSLATE_GENERIC_DEBUG_LOG_TRANSFERS)
+ translate_generic_service_log_connect(message);
+
++ if (deadline) {
++ soup_session_queue_message(info.session, message, send_message_cb, &completed);
++
++ do {
++ g_main_iteration (FALSE);
++ if (completed) break;
++
++ g_get_current_time(&tv);
++ } while ((tv.tv_sec < deadline->tv_sec)||((tv.tv_sec == deadline->tv_sec)&&(tv.tv_usec < deadline->tv_usec)));
++
++ if (!completed) {
++#ifdef HAVE_LIBSOUP22
++ soup_session_cancel_message(info.session, message);
++#else
++ soup_session_cancel_message(info.session, message, SOUP_STATUS_CANCELLED);
++#endif
++ canceled = 1;
++ }
++ } else
+ soup_session_send_message(info.session, message);
+ g_object_unref(info.session);
+
++ if (canceled)
++ g_set_error(err, TRANSLATE_ERROR, TRANSLATE_ERROR_CANCELLED, _("Timeout"));
++ else
+ if (SOUP_STATUS_IS_SUCCESSFUL(message->status_code))
+ {
+ const char *charset = NULL;
+@@ -833,10 +870,11 @@
+ }
+
+ static char *
+-translate_generic_service_translate_text (TranslateService *service,
++translate_generic_service_timed_translate_text (TranslateService *service,
+ const char *text,
+ const char *from,
+ const char *to,
++ GTimeVal *deadline,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err)
+@@ -882,16 +920,16 @@
+
+ headers = g_slist_copy(group->http_headers);
+ headers = g_slist_concat(headers, g_slist_copy(group->text_location->http_headers));
+-
++
+ response = translate_generic_service_get(url,
+ post,
+ group->text_location->content_type,
+ headers,
+ TRANSFER_FOLLOW_REFRESH | TRANSFER_CONVERT,
++ deadline,
+ progress_func,
+ user_data,
+ err);
+-
+ g_free(url);
+ g_free(post);
+ g_slist_free(headers);
+@@ -991,6 +1029,18 @@
+ return answer ? g_string_free(answer, FALSE) : NULL;
+ }
+
++static char *
++translate_generic_service_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err)
++{
++ return translate_generic_service_timed_translate_text(service, text, from, to, NULL, progress_func, user_data, err);
++}
++
+ char *
+ translate_generic_service_expand (const char *warning_prefix,
+ const char *str,
+@@ -1252,6 +1302,7 @@
+ group->web_page_location->content_type,
+ headers,
+ 0,
++ NULL,
+ progress_func,
+ user_data,
+ err);
+@@ -1311,7 +1362,7 @@
+ g_free(proxy_text_uri);
+ }
+
+- session = soup_session_sync_new_with_options(SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
++ session = soup_session_async_new_with_options(SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
+
+ if (proxy_uri)
+ soup_uri_free(proxy_uri);
+diff -dPNur libtranslate-0.99/src/translate-service.c libtranslate-0.99-new/src/translate-service.c
+--- libtranslate-0.99/src/translate-service.c 2005-01-17 17:45:23.000000000 +0100
++++ libtranslate-0.99-new/src/translate-service.c 2005-07-27 17:18:07.000000000 +0200
+@@ -372,6 +372,28 @@
+ }
+
+ char *
++translate_service_timed_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err)
++{
++ g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL);
++ g_return_val_if_fail(TRANSLATE_SERVICE_GET_CLASS(service)->translate_text != NULL, NULL);
++ g_return_val_if_fail(text != NULL, NULL);
++ g_return_val_if_fail(from != NULL, NULL);
++ g_return_val_if_fail(to != NULL, NULL);
++
++ if (TRANSLATE_SERVICE_GET_CLASS(service)->timed_translate_text)
++ return TRANSLATE_SERVICE_GET_CLASS(service)->timed_translate_text(service, text, from, to, deadline, progress_func, user_data, err);
++
++ return TRANSLATE_SERVICE_GET_CLASS(service)->translate_text(service, text, from, to, progress_func, user_data, err);
++}
++
++char *
+ translate_service_translate_web_page (TranslateService *service,
+ const char *url,
+ const char *from,
+diff -dPNur libtranslate-0.99/src/translate-service.h libtranslate-0.99-new/src/translate-service.h
+--- libtranslate-0.99/src/translate-service.h 2005-01-17 17:45:29.000000000 +0100
++++ libtranslate-0.99-new/src/translate-service.h 2005-07-27 16:54:46.000000000 +0200
+@@ -73,6 +73,14 @@
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err);
++ char *(*timed_translate_text)(TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
+ char *(*translate_web_page) (TranslateService *service,
+ const char *url,
+ const char *from,
+diff -dPNur libtranslate-0.99/src/translate-service-private.h libtranslate-0.99-new/src/translate-service-private.h
+--- libtranslate-0.99/src/translate-service-private.h 2005-01-17 17:45:17.000000000 +0100
++++ libtranslate-0.99-new/src/translate-service-private.h 2005-07-27 17:30:00.000000000 +0200
+@@ -41,6 +41,14 @@
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err);
++char *translate_service_timed_translate_text (TranslateService *service,
++ const char *text,
++ const char *from,
++ const char *to,
++ GTimeVal *deadline,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
+ char *translate_service_translate_web_page (TranslateService *service,
+ const char *url,
+ const char *from,
+diff -dPNur libtranslate-0.99/src/translate-session.c libtranslate-0.99-new/src/translate-session.c
+--- libtranslate-0.99/src/translate-session.c 2005-01-17 17:45:35.000000000 +0100
++++ libtranslate-0.99-new/src/translate-session.c 2005-07-27 16:52:46.000000000 +0200
+@@ -62,6 +62,8 @@
+ {
+ GMutex *mutex;
+ GCond *progress_cond;
++
++ GTimeVal *deadline;
+
+ TranslateSession *session;
+ GSList *services;
+@@ -487,6 +489,7 @@
+ * @text: a nul-terminated string.
+ * @from: a RFC 3066 language tag.
+ * @to: a RFC 3066 language tag.
++ * @timeout: timeout in microseconds.
+ * @progress_func: a function to call when progressing, or %NULL.
+ * @user_data: data to pass to @progress_func, or %NULL.
+ * @err: a location to report errors, or %NULL. Any of the errors in
+@@ -505,10 +508,11 @@
+ * when no longer needed.
+ **/
+ char *
+-translate_session_translate_text (TranslateSession *session,
++translate_session_timed_translate_text (TranslateSession *session,
+ const char *text,
+ const char *from,
+ const char *to,
++ gulong timeout,
+ TranslateProgressFunc progress_func,
+ gpointer user_data,
+ GError **err)
+@@ -519,6 +523,7 @@
+ unsigned int max_threads;
+ GThreadPool *pool;
+ GSList *l;
++ GTimeVal deadline;
+ unsigned int max_chunk_len = 0;
+ char *translated = NULL;
+
+@@ -527,6 +532,11 @@
+ g_return_val_if_fail(from != NULL, NULL);
+ g_return_val_if_fail(to != NULL, NULL);
+
++ if (timeout) {
++ g_get_current_time(&deadline);
++ g_time_val_add(&deadline, timeout);
++ }
++
+ LOCK(session);
+ info.services = translate_session_get_services_for_translation(session,
+ TRANSLATE_PAIR_TEXT,
+@@ -560,7 +570,8 @@
+ chunks = translate_session_split(text, max_chunk_len);
+
+ info.mutex = g_mutex_new();
+- info.progress_cond = progress_func ? g_cond_new() : NULL;
++ info.progress_cond = (progress_func||timeout) ? g_cond_new() : NULL;
++ info.deadline = timeout ? &deadline : NULL;
+ info.session = session;
+ info.chunks = NULL;
+ info.from = from;
+@@ -614,6 +625,11 @@
+ GSList *l;
+ int n_chunks;
+
++ if (timeout) {
++ if (!g_cond_timed_wait(info.progress_cond, info.mutex, info.deadline))
++ info.err = g_error_new(TRANSLATE_ERROR,TRANSLATE_ERROR_CANCELLED,_("timeout"));
++ break;
++ } else
+ g_cond_wait(info.progress_cond, info.mutex);
+
+ if (info.err)
+@@ -680,6 +696,18 @@
+ return translated;
+ }
+
++char *
++translate_session_translate_text (TranslateSession *session,
++ const char *text,
++ const char *from,
++ const char *to,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err)
++{
++ return translate_session_timed_translate_text(session, text, from, to, 0, progress_func, user_data, err);
++}
++
+ static void
+ translate_session_translate_thread (gpointer data, gpointer user_data)
+ {
+@@ -709,10 +737,11 @@
+ if (ret)
+ return;
+
+- chunk_info->translated = translate_service_translate_text(service,
++ chunk_info->translated = translate_service_timed_translate_text(service,
+ chunk_info->chunk,
+ info->from,
+ info->to,
++ info->deadline,
+ info->progress_cond ? translate_session_translate_progress_cb : NULL,
+ info->progress_cond ? chunk_info : NULL,
+ &tmp_err);
+diff -dPNur libtranslate-0.99/src/translate-session.h libtranslate-0.99-new/src/translate-session.h
+--- libtranslate-0.99/src/translate-session.h 2005-01-17 17:45:40.000000000 +0100
++++ libtranslate-0.99-new/src/translate-session.h 2005-07-27 14:41:05.000000000 +0200
+@@ -93,6 +93,14 @@
+ unsigned int translate_session_get_max_threads (TranslateSession *session);
+ int translate_session_get_max_retries (TranslateSession *session);
+
++char *translate_session_timed_translate_text (TranslateSession *session,
++ const char *text,
++ const char *from,
++ const char *to,
++ gulong timeout,
++ TranslateProgressFunc progress_func,
++ gpointer user_data,
++ GError **err);
+ char *translate_session_translate_text (TranslateSession *session,
+ const char *text,
+ const char *from,
diff --git a/patches/libtranslate/soup24/libtranslate-ds8-soup24inc.patch b/patches/libtranslate/soup24/libtranslate-ds8-soup24inc.patch
new file mode 100644
index 0000000..8de7c07
--- /dev/null
+++ b/patches/libtranslate/soup24/libtranslate-ds8-soup24inc.patch
@@ -0,0 +1,533 @@
+diff -dPNur libtranslate-0.99/config.h.in libtranslate-0.99-1/config.h.in
+--- libtranslate-0.99/config.h.in 2005-01-17 18:06:58.000000000 +0100
++++ libtranslate-0.99-1/config.h.in 2010-02-14 03:55:56.000000000 +0100
+@@ -24,6 +24,12 @@
+ /* Define if your <locale.h> file defines LC_MESSAGES. */
+ #undef HAVE_LC_MESSAGES
+
++/* Building with libsoup 2.2 */
++#undef HAVE_LIBSOUP22
++
++/* Building with libsoup 2.4 */
++#undef HAVE_LIBSOUP24
++
+ /* Define to 1 if you have the <locale.h> header file. */
+ #undef HAVE_LOCALE_H
+
+diff -dPNur libtranslate-0.99/configure.ac libtranslate-0.99-1/configure.ac
+--- libtranslate-0.99/configure.ac 2005-01-15 17:24:12.000000000 +0100
++++ libtranslate-0.99-1/configure.ac 2010-02-14 03:55:56.000000000 +0100
+@@ -50,7 +50,11 @@
+ ### optional libraries
+
+ if TRANSLATE_FEATURE_ENABLED(generic); then
+- PKG_CHECK_MODULES(SOUP, [libsoup-2.2],, [TRANSLATE_FEATURE_DISABLE(generic, [libsoup not found])])
++ PKG_CHECK_MODULES(SOUP, [libsoup-2.4],
++ [AC_DEFINE(HAVE_LIBSOUP24, 1, [Building with libsoup 2.4])],
++ [PKG_CHECK_MODULES(SOUP, [libsoup-2.2],
++ [AC_DEFINE(HAVE_LIBSOUP22, 1, [Building with libsoup 2.2])],
++ [TRANSLATE_FEATURE_DISABLE(generic, [libsoup not found])])])
+ fi
+ if TRANSLATE_FEATURE_ENABLED(generic); then
+ PKG_CHECK_MODULES(LIBXML, [libxml-2.0],, [TRANSLATE_FEATURE_DISABLE(generic, [libxml not found])])
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-service.c libtranslate-0.99-1/src/modules/translate-generic-service.c
+--- libtranslate-0.99/src/modules/translate-generic-service.c 2010-02-14 03:55:34.000000000 +0100
++++ libtranslate-0.99-1/src/modules/translate-generic-service.c 2010-02-14 04:04:56.000000000 +0100
+@@ -35,7 +35,9 @@
+ #include <stdlib.h>
+ #include <glib/gi18n-lib.h>
+ #include <libsoup/soup.h>
++#ifdef HAVE_LIBSOUP22
+ #include <libsoup/soup-message-filter.h>
++#endif
+ #include <libxml/HTMLparser.h>
+ #include "translate.h"
+ #include "translate-generic-service.h"
+@@ -43,6 +45,17 @@
+ #include "translate-generic-parser.h"
+ #include "translate-generic-soup-cookie-jar.h"
+
++#ifdef HAVE_LIBSOUP22
++#define soup_message_headers_get soup_message_get_header
++#define soup_message_headers_append soup_message_add_header
++#define SoupURI SoupUri
++#define SOUP_MESSAGE_RESPONSE_BODY(msg) ((msg)->response.body)
++#define SOUP_MESSAGE_RESPONSE_LENGTH(msg) ((msg)->response.length)
++#else
++#define SOUP_MESSAGE_RESPONSE_BODY(msg) ((msg)->response_body->data)
++#define SOUP_MESSAGE_RESPONSE_LENGTH(msg) ((msg)->response_body->length)
++#endif
++
+ #define MAKE_WARNING_PREFIX(service, group_pos, attribute, element) \
+ g_strdup_printf(_("in %s, group %i, \"%s\" attribute of \"%s\" element"), \
+ translate_service_get_name((service)), \
+@@ -142,6 +155,7 @@
+ const char *name);
+
+ static void translate_generic_service_log_connect (SoupMessage *message);
++#ifdef HAVE_LIBSOUP22
+ static void translate_generic_service_log_wrote_headers_h (SoupMessage *message,
+ gpointer user_data);
+ static void translate_generic_service_log_wrote_body_h (SoupMessage *message,
+@@ -153,10 +167,20 @@
+ static void translate_generic_service_log_headers_cb (const char *key,
+ const char *value,
+ gpointer user_data);
++#else
++static void translate_generic_service_log_printer (SoupLogger *logger,
++ SoupLoggerLogLevel level,
++ char direction,
++ const char *data,
++ gpointer user_data);
++#endif
+
+ static void translate_generic_service_progress_got_headers_h (SoupMessage *message,
+ gpointer user_data);
+ static void translate_generic_service_progress_got_chunk_h (SoupMessage *message,
++#ifdef HAVE_LIBSOUP24
++ SoupBuffer *chunk,
++#endif
+ gpointer user_data);
+
+ static void translate_generic_service_html_got_headers_h (SoupMessage *message,
+@@ -172,8 +196,10 @@
+ static void translate_generic_service_refresh_got_body_h (SoupMessage *message,
+ gpointer user_data);
+
++#ifdef HAVE_LIBSOUP22
+ static void translate_generic_service_redirect_handler (SoupMessage *message,
+ gpointer user_data);
++#endif
+
+ static char *translate_generic_service_translate_text (TranslateService *service,
+ const char *text,
+@@ -440,7 +466,11 @@
+ g_return_val_if_fail(post_content_type != NULL, NULL);
+ soup_message_set_request(message,
+ post_content_type,
++#ifdef HAVE_LIBSOUP22
+ SOUP_BUFFER_USER_OWNED,
++#else
++ SOUP_MEMORY_TEMPORARY,
++#endif
+ (char *) post,
+ strlen(post));
+ }
+@@ -448,7 +478,7 @@
+ for (l = headers; l != NULL; l = l->next)
+ {
+ TranslateGenericHttpHeader *header = l->data;
+- soup_message_add_header(message->request_headers, header->name, header->value);
++ soup_message_headers_append(message->request_headers, header->name, header->value);
+ }
+
+ info.session = translate_generic_service_soup_session_sync_new();
+@@ -456,12 +486,21 @@
+ info.html_http_equiv = NULL;
+
+ if (translate_generic_debug_flags & TRANSLATE_GENERIC_DEBUG_LOG_TRANSFERS)
+- g_object_connect(message,
+- "signal::wrote-headers", translate_generic_service_log_wrote_headers_h, &info,
+- "signal::wrote-body", translate_generic_service_log_wrote_body_h, &info,
+- "signal::got-headers", translate_generic_service_log_got_headers_h, &info,
+- "signal::got-body", translate_generic_service_log_got_body_h, &info,
+- NULL);
++ {
++#ifdef HAVE_LIBSOUP22
++ g_object_connect(message,
++ "signal::wrote-headers", translate_generic_service_log_wrote_headers_h, &info,
++ "signal::wrote-body", translate_generic_service_log_wrote_body_h, &info,
++ "signal::got-headers", translate_generic_service_log_got_headers_h, &info,
++ "signal::got-body", translate_generic_service_log_got_body_h, &info,
++ NULL);
++#else
++ SoupLogger *logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
++ soup_logger_set_printer (logger, translate_generic_service_log_printer, NULL, NULL);
++ soup_logger_attach (logger, info.session);
++ g_object_unref (logger);
++#endif
++ }
+
+ if (progress_func)
+ {
+@@ -489,6 +528,7 @@
+ if (flags & TRANSFER_FOLLOW_REFRESH)
+ g_signal_connect(message, "got-body", G_CALLBACK(translate_generic_service_refresh_got_body_h), &info);
+
++#ifdef HAVE_LIBSOUP22
+ /* http://bugzilla.ximian.com/show_bug.cgi?id=70688 */
+ soup_message_set_flags(message, SOUP_MESSAGE_NO_REDIRECT);
+ soup_message_add_status_class_handler(message,
+@@ -496,6 +536,7 @@
+ SOUP_HANDLER_POST_BODY,
+ translate_generic_service_redirect_handler,
+ info.session);
++#endif
+
+ if (translate_generic_debug_flags & TRANSLATE_GENERIC_DEBUG_LOG_TRANSFERS)
+ translate_generic_service_log_connect(message);
+@@ -554,18 +595,18 @@
+
+ if ((charset)||(response_charset))
+ {
+- response = g_convert(message->response.body, message->response.length, "UTF-8", response_charset?response_charset:charset, NULL, NULL, err);
++ response = g_convert(SOUP_MESSAGE_RESPONSE_BODY (message), SOUP_MESSAGE_RESPONSE_LENGTH (message), "UTF-8", charset, NULL, NULL, err);
+ g_free(charset);
+ }
+ else
+ {
+- if ((flags & TRANSFER_CONVERT) && ! g_utf8_validate(message->response.body, message->response.length, NULL))
++ if ((flags & TRANSFER_CONVERT) && ! g_utf8_validate(SOUP_MESSAGE_RESPONSE_BODY (message), SOUP_MESSAGE_RESPONSE_LENGTH (message), NULL))
+ g_set_error(err,
+ TRANSLATE_GENERIC_SERVICE_ERROR,
+ TRANSLATE_GENERIC_SERVICE_ERROR_TRANSFER,
+ _("invalid UTF-8"));
+ else
+- response = g_strndup(message->response.body, message->response.length);
++ response = g_strndup(SOUP_MESSAGE_RESPONSE_BODY (message), SOUP_MESSAGE_RESPONSE_LENGTH (message));
+ }
+ }
+ else
+@@ -606,7 +647,7 @@
+ : NULL;
+
+ if (! value)
+- value = soup_message_get_header(message->response_headers, name);
++ value = soup_message_headers_get(message->response_headers, name);
+
+ return value;
+ }
+@@ -614,12 +655,14 @@
+ static void
+ translate_generic_service_log_connect (SoupMessage *message)
+ {
+- const SoupUri *uri;
++ const SoupURI *uri;
+
+ uri = soup_message_get_uri(message);
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, _("connecting to %s:%i"), uri->host, uri->port);
+ }
+
++#ifdef HAVE_LIBSOUP22
++
+ static void
+ translate_generic_service_log_wrote_headers_h (SoupMessage *message,
+ gpointer user_data)
+@@ -674,6 +717,20 @@
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s: %s", prefix, key, value);
+ }
+
++#else /* !HAVE_LIBSOUP22 */
++
++static void
++translate_generic_service_log_printer (SoupLogger *logger,
++ SoupLoggerLogLevel level,
++ char direction,
++ const char *data,
++ gpointer user_data)
++{
++ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%c %s", direction, data);
++}
++
++#endif /* HAVE_LIBSOUP22 */
++
+ static void
+ translate_generic_service_progress_got_headers_h (SoupMessage *message,
+ gpointer user_data)
+@@ -681,7 +738,7 @@
+ TransferInfo *info = user_data;
+ const char *content_length;
+
+- content_length = soup_message_get_header(message->response_headers, "Content-Length");
++ content_length = soup_message_headers_get(message->response_headers, "Content-Length");
+ info->length = (content_length
+ && *content_length
+ && strspn(content_length, "0123456789") == strlen(content_length))
+@@ -691,6 +748,9 @@
+
+ static void
+ translate_generic_service_progress_got_chunk_h (SoupMessage *message,
++#ifdef HAVE_LIBSOUP24
++ SoupBuffer *chunk,
++#endif
+ gpointer user_data)
+ {
+ TransferInfo *info = user_data;
+@@ -700,7 +760,11 @@
+ progress = -1;
+ else
+ {
++#ifdef HAVE_LIBSOUP22
+ info->received += message->response.length;
++#else
++ info->received += chunk->length;
++#endif
+ progress = (double) info->received / info->length;
+ progress = CLAMP(progress, 0.0, 1.0);
+ }
+@@ -716,7 +780,7 @@
+ TransferInfo *info = user_data;
+ const char *content_type;
+
+- content_type = soup_message_get_header(message->response_headers, "Content-Type");
++ content_type = soup_message_headers_get(message->response_headers, "Content-Type");
+ info->parse_html = content_type
+ && (g_str_has_prefix(content_type, "text/html")
+ || g_str_has_prefix(content_type, "application/xhtml+xml")
+@@ -736,7 +800,7 @@
+ info->html_http_equiv = NULL;
+ }
+
+- if (info->parse_html && message->response.length > 0)
++ if (info->parse_html && SOUP_MESSAGE_RESPONSE_LENGTH (message) > 0)
+ {
+ char *body;
+ xmlSAXHandler sax_handler = { NULL };
+@@ -750,7 +814,7 @@
+ sax_handler.startElement = translate_generic_service_html_start_element_cb;
+ sax_handler.endElement = translate_generic_service_html_end_element_cb;
+
+- body = g_strndup(message->response.body, message->response.length);
++ body = g_strndup(SOUP_MESSAGE_RESPONSE_BODY (message), SOUP_MESSAGE_RESPONSE_LENGTH (message));
+ htmlSAXParseDoc(body, NULL, &sax_handler, user_data);
+ g_free(body);
+ }
+@@ -817,7 +881,7 @@
+ {
+ TransferInfo *info = user_data;
+ const char *refresh_uri;
+- SoupUri *new_uri = NULL;
++ SoupURI *new_uri = NULL;
+
+ refresh_uri = translate_generic_service_get_header(message, info, "Refresh");
+ if (refresh_uri)
+@@ -832,9 +896,9 @@
+ new_uri = soup_uri_new(refresh_uri);
+ if (! new_uri)
+ {
+- const SoupUri *base_uri;
++ SoupURI *base_uri;
+
+- base_uri = soup_message_get_uri(message);
++ base_uri = (SoupURI *)soup_message_get_uri(message);
+ new_uri = soup_uri_new_with_base(base_uri, refresh_uri);
+ }
+ }
+@@ -851,6 +915,7 @@
+ }
+ }
+
++#ifdef HAVE_LIBSOUP22
+ static void
+ translate_generic_service_redirect_handler (SoupMessage *message,
+ gpointer user_data)
+@@ -887,6 +952,7 @@
+ soup_session_requeue_message(session, message);
+ }
+ }
++#endif
+
+ static char *
+ translate_generic_service_timed_translate_text (TranslateService *service,
+@@ -1391,7 +1457,7 @@
+ translate_generic_service_soup_session_sync_new (void)
+ {
+ char *proxy_text_uri;
+- SoupUri *proxy_uri = NULL;
++ SoupURI *proxy_uri = NULL;
+ SoupSession *session;
+ TranslateGenericSoupCookieJar *cookie_jar;
+
+@@ -1411,7 +1477,7 @@
+ soup_uri_free(proxy_uri);
+
+ cookie_jar = translate_generic_soup_cookie_jar_new();
+- soup_session_add_filter(session, SOUP_MESSAGE_FILTER(cookie_jar));
++ translate_generic_soup_cookie_jar_attach(cookie_jar, session);
+ g_object_unref(cookie_jar);
+
+ return session;
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-soup-cookie-jar.c libtranslate-0.99-1/src/modules/translate-generic-soup-cookie-jar.c
+--- libtranslate-0.99/src/modules/translate-generic-soup-cookie-jar.c 2005-01-17 17:46:53.000000000 +0100
++++ libtranslate-0.99-1/src/modules/translate-generic-soup-cookie-jar.c 2010-02-14 03:55:56.000000000 +0100
+@@ -29,9 +29,12 @@
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
++#include "config.h"
+ #include <string.h>
+ #include <libsoup/soup.h>
++#ifdef HAVE_LIBSOUP22
+ #include <libsoup/soup-message-filter.h>
++#endif
+ #include "translate-generic-soup-cookie-jar.h"
+
+ struct _TranslateGenericSoupCookieJarPrivate
+@@ -44,9 +47,12 @@
+ static void translate_generic_soup_cookie_jar_register_type (GType *type);
+ static void translate_generic_soup_cookie_jar_class_init (TranslateGenericSoupCookieJarClass *class);
+ static void translate_generic_soup_cookie_jar_init (TranslateGenericSoupCookieJar *jar);
++#ifdef HAVE_LIBSOUP22
+ static void translate_generic_soup_cookie_jar_filter_init (SoupMessageFilterClass *iface);
++#else
++#define SoupMessageFilter TranslateGenericSoupCookieJar
++#endif
+ static void translate_generic_soup_cookie_jar_finalize (GObject *object);
+-
+ static void translate_generic_soup_cookie_jar_setup_message (SoupMessageFilter *filter,
+ SoupMessage *message);
+
+@@ -75,17 +81,21 @@
+ 0,
+ (GInstanceInitFunc) translate_generic_soup_cookie_jar_init
+ };
++#ifdef HAVE_LIBSOUP22
+ static const GInterfaceInfo filter_info = {
+ (GInterfaceInitFunc) translate_generic_soup_cookie_jar_filter_init,
+ NULL,
+ NULL
+ };
++#endif
+
+ *type = g_type_register_static(G_TYPE_OBJECT,
+ "TranslateGenericSoupCookieJar",
+ &info,
+ 0);
++#ifdef HAVE_LIBSOUP22
+ g_type_add_interface_static(*type, SOUP_TYPE_MESSAGE_FILTER, &filter_info);
++#endif
+ }
+
+ static void
+@@ -107,11 +117,13 @@
+ TranslateGenericSoupCookieJarPrivate);
+ }
+
++#ifdef HAVE_LIBSOUP22
+ static void
+ translate_generic_soup_cookie_jar_filter_init (SoupMessageFilterClass *iface)
+ {
+ iface->setup_message = translate_generic_soup_cookie_jar_setup_message;
+ }
++#endif
+
+ static void
+ translate_generic_soup_cookie_jar_finalize (GObject *object)
+@@ -125,26 +137,46 @@
+ }
+
+ static void
++add_cookie_to_jar (TranslateGenericSoupCookieJar *jar, const char *cookie)
++{
++ char *s;
++
++ s = strchr(cookie, ';');
++ if (s)
++ jar->priv->cookies = g_slist_append(jar->priv->cookies, g_strndup(cookie, s - cookie));
++}
++
++#ifdef HAVE_LIBSOUP24
++static void
++maybe_add_cookie_to_jar (const char *header, const char *value, gpointer jar)
++{
++ if (!g_ascii_strcasecmp (header, "Set-Cookie"))
++ add_cookie_to_jar (jar, value);
++}
++#endif
++
++static void
+ translate_generic_soup_cookie_jar_setup_message (SoupMessageFilter *filter,
+- SoupMessage *message)
++ SoupMessage *message)
+ {
+ TranslateGenericSoupCookieJar *jar = TRANSLATE_GENERIC_SOUP_COOKIE_JAR(filter);
+- const GSList *cookies;
+ const GSList *l;
+
+ /* FIXME: add full RFC 2965 support */
+
++#ifdef HAVE_LIBSOUP22
++ const GSList *cookies;
++
+ cookies = soup_message_get_header_list(message->response_headers, "Set-Cookie");
+ for (l = cookies; l != NULL; l = l->next)
+ {
+ const char *cookie = l->data;
+- char *s;
+-
+- s = strchr(cookie, ';');
+- if (s)
+- jar->priv->cookies = g_slist_append(jar->priv->cookies, g_strndup(cookie, s - cookie));
++ add_cookie_to_jar(jar, cookie);
+ }
+-
++#else
++ soup_message_headers_foreach(message->response_headers, maybe_add_cookie_to_jar, jar);
++#endif
++
+ if (jar->priv->cookies)
+ {
+ GString *string;
+@@ -159,13 +191,44 @@
+ g_string_append(string, "; ");
+ }
+
++#ifdef HAVE_LIBSOUP22
+ soup_message_add_header(message->request_headers, "Cookie", string->str);
++#else
++ soup_message_headers_append(message->request_headers, "Cookie", string->str);
++#endif
+ g_string_free(string, TRUE);
+ }
+ }
+
++#ifdef HAVE_LIBSOUP24
++static void
++translate_generic_soup_cookie_jar_request_started (SoupSession *session,
++ SoupMessage *message,
++ SoupSocket *socket,
++ gpointer cookie_jar)
++{
++ translate_generic_soup_cookie_jar_setup_message (cookie_jar, message);
++}
++#endif
++
+ TranslateGenericSoupCookieJar *
+ translate_generic_soup_cookie_jar_new (void)
+ {
+ return g_object_new(TRANSLATE_GENERIC_TYPE_SOUP_COOKIE_JAR, NULL);
+ }
++
++void
++translate_generic_soup_cookie_jar_attach (TranslateGenericSoupCookieJar *cookie_jar,
++ SoupSession *session)
++{
++#ifdef HAVE_LIBSOUP22
++ soup_session_add_filter (session, SOUP_MESSAGE_FILTER(cookie_jar));
++#else
++ g_signal_connect (session, "request_started",
++ G_CALLBACK (translate_generic_soup_cookie_jar_request_started),
++ cookie_jar);
++ g_object_set_data_full (G_OBJECT (session), "TranslateGenericSoupCookieJar",
++ g_object_ref (cookie_jar), g_object_unref);
++#endif
++}
++
+diff -dPNur libtranslate-0.99/src/modules/translate-generic-soup-cookie-jar.h libtranslate-0.99-1/src/modules/translate-generic-soup-cookie-jar.h
+--- libtranslate-0.99/src/modules/translate-generic-soup-cookie-jar.h 2005-01-17 17:47:00.000000000 +0100
++++ libtranslate-0.99-1/src/modules/translate-generic-soup-cookie-jar.h 2010-02-14 03:55:56.000000000 +0100
+@@ -33,6 +33,7 @@
+ #define _TRANSLATE_GENERIC_SOUP_COOKIE_JAR_H
+
+ #include <glib-object.h>
++#include <libsoup/soup-session.h>
+
+ #define TRANSLATE_GENERIC_TYPE_SOUP_COOKIE_JAR (translate_generic_soup_cookie_jar_get_type())
+ #define TRANSLATE_GENERIC_SOUP_COOKIE_JAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TRANSLATE_GENERIC_TYPE_SOUP_COOKIE_JAR, TranslateGenericSoupCookieJar))
+@@ -59,5 +60,6 @@
+
+ GType translate_generic_soup_cookie_jar_get_type (void);
+ TranslateGenericSoupCookieJar *translate_generic_soup_cookie_jar_new (void);
++void translate_generic_soup_cookie_jar_attach (TranslateGenericSoupCookieJar *cookie_jar, SoupSession *session);
+
+ #endif /* _TRANSLATE_GENERIC_SOUP_COOKIE_JAR_H */
diff --git a/patches/mpg123/mpg123-ds-rcc.patch b/patches/mpg123/mpg123-ds-rcc.patch
new file mode 100644
index 0000000..bbfd104
--- /dev/null
+++ b/patches/mpg123/mpg123-ds-rcc.patch
@@ -0,0 +1,151 @@
+diff -dPNur mpg123-0.59r/common.c mpg123-0.59r-new/common.c
+--- mpg123-0.59r/common.c 1999-06-15 23:24:19.000000000 +0200
++++ mpg123-0.59r-new/common.c 2005-09-16 02:48:11.000000000 +0200
+@@ -15,6 +15,7 @@
+ #endif
+ #endif
+
++#include "rccpatch.h"
+ #include "mpg123.h"
+ #include "genre.h"
+ #include "common.h"
+@@ -484,6 +485,8 @@
+ char comment[31]={0,};
+ char genre[31]={0,};
+
++ char *ctitle, *cartist, *calbum, *ccomment;
++
+ if(param.quiet)
+ return;
+
+@@ -492,16 +495,26 @@
+ strncpy(album,tag->album,30);
+ strncpy(year,tag->year,4);
+ strncpy(comment,tag->comment,30);
++
++ ctitle = rccPatchRecode(title);
++ cartist = rccPatchRecode(artist);
++ calbum = rccPatchRecode(album);
++ ccomment = rccPatchRecode(comment);
+
+- if ( tag->genre <= sizeof(genre_table)/sizeof(*genre_table) ) {
++ if ( tag->genre < sizeof(genre_table)/sizeof(*genre_table) ) {
+ strncpy(genre, genre_table[tag->genre], 30);
+ } else {
+ strncpy(genre,"Unknown",30);
+ }
+
+- fprintf(stderr,"Title : %-30s Artist: %s\n",title,artist);
+- fprintf(stderr,"Album : %-30s Year : %4s\n",album,year);
+- fprintf(stderr,"Comment: %-30s Genre : %s\n",comment,genre);
++ fprintf(stderr,"Title : %-30s Artist: %s\n",ctitle?ctitle:title,cartist?cartist:artist);
++ fprintf(stderr,"Album : %-30s Year : %4s\n",calbum?calbum:album,year);
++ fprintf(stderr,"Comment: %-30s Genre : %s\n",ccomment?ccomment:comment,genre);
++
++ if (ctitle) free(ctitle);
++ if (cartist) free(cartist);
++ if (calbum) free(calbum);
++ if (ccomment) free(ccomment);
+ }
+
+ #if 0
+diff -dPNur mpg123-0.59r/Makefile mpg123-0.59r-new/Makefile
+--- mpg123-0.59r/Makefile 1999-06-18 14:18:58.000000000 +0200
++++ mpg123-0.59r-new/Makefile 2005-09-16 02:47:47.000000000 +0200
+@@ -554,12 +554,12 @@
+ mpg123-make:
+ @ $(MAKE) CFLAGS='$(CFLAGS)' BINNAME=mpg123 mpg123
+
+-mpg123: mpg123.o common.o $(OBJECTS) decode_2to1.o decode_4to1.o \
++mpg123: mpg123.o rccpatch.o common.o $(OBJECTS) decode_2to1.o decode_4to1.o \
+ tabinit.o audio.o layer1.o layer2.o layer3.o buffer.o \
+ getlopt.o httpget.o xfermem.o equalizer.o \
+ decode_ntom.o Makefile wav.o readers.o getbits.o \
+ control_generic.o
+- $(CC) $(CFLAGS) $(LDFLAGS) mpg123.o tabinit.o common.o layer1.o \
++ $(CC) $(CFLAGS) $(LDFLAGS) -lrcc mpg123.o tabinit.o rccpatch.o common.o layer1.o \
+ layer2.o layer3.o audio.o buffer.o decode_2to1.o equalizer.o \
+ decode_4to1.o getlopt.o httpget.o xfermem.o decode_ntom.o \
+ wav.o readers.o getbits.o control_generic.o \
+diff -dPNur mpg123-0.59r/mpg123.c mpg123-0.59r-new/mpg123.c
+--- mpg123-0.59r/mpg123.c 1999-06-18 14:18:11.000000000 +0200
++++ mpg123-0.59r-new/mpg123.c 2005-09-16 02:47:47.000000000 +0200
+@@ -32,6 +32,8 @@
+ #include "buffer.h"
+ #include "term.h"
+
++#include "rccpatch.h"
++
+ #include "version.h"
+
+ static void usage(char *dummy);
+@@ -903,6 +905,8 @@
+ exit(0);
+ }
+ #endif
++
++ rccPatchInit();
+
+ while ((fname = get_next_file(argc, argv))) {
+ char *dirname, *filename;
+@@ -1068,6 +1072,8 @@
+ intflag = FALSE;
+ }
+ }
++ rccPatchFree();
++
+ #ifndef NOXFERMEM
+ if (param.usebuffer) {
+ buffer_end();
+diff -dPNur mpg123-0.59r/rccpatch.c mpg123-0.59r-new/rccpatch.c
+--- mpg123-0.59r/rccpatch.c 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-0.59r-new/rccpatch.c 2005-09-16 02:47:47.000000000 +0200
+@@ -0,0 +1,40 @@
++#include <librcc.h>
++
++#define ID3_CLASS 0
++#define OUT_CLASS 1
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, NULL, NULL, "Output Encoding", 0 },
++ { NULL }
++};
++
++static int rcc_initialized = 0;
++
++void rccPatchFree() {
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++}
++
++void rccPatchInit() {
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++}
++
++static void rccPatchTryInit() {
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++}
++
++char *rccPatchRecode(const char *str) {
++ char *res;
++ rccPatchTryInit();
++ return rccRecode(NULL, ID3_CLASS, OUT_CLASS, str);
++}
+diff -dPNur mpg123-0.59r/rccpatch.h mpg123-0.59r-new/rccpatch.h
+--- mpg123-0.59r/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-0.59r-new/rccpatch.h 2005-09-16 02:47:47.000000000 +0200
+@@ -0,0 +1,4 @@
++void rccPatchFree();
++void rccPatchInit();
++char *rccPatchRecode(const char *str);
++
diff --git a/patches/mpg123/mpg123-ds-rcc1121.patch b/patches/mpg123/mpg123-ds-rcc1121.patch
new file mode 100644
index 0000000..1335795
--- /dev/null
+++ b/patches/mpg123/mpg123-ds-rcc1121.patch
@@ -0,0 +1,247 @@
+diff -dPNur mpg123-1.12.1/configure.ac mpg123-1.12.1-new/configure.ac
+--- mpg123-1.12.1/configure.ac 2010-03-31 10:27:37.000000000 +0200
++++ mpg123-1.12.1-new/configure.ac 2010-07-07 23:44:57.000000000 +0200
+@@ -998,6 +998,21 @@
+ AC_CHECK_LIB([m], [sqrt])
+ AC_CHECK_LIB([mx], [powf])
+
++# LibRCC
++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)
++
+ # attempt to make the signal stuff work... also with GENERIC - later
+ #if test x"$ac_cv_header_sys_signal_h" = xyes; then
+ # AC_CHECK_FUNCS( sigemptyset sigaddset sigprocmask sigaction )
+diff -dPNur mpg123-1.12.1/src/libmpg123/id3.c mpg123-1.12.1-new/src/libmpg123/id3.c
+--- mpg123-1.12.1/src/libmpg123/id3.c 2010-03-31 10:27:35.000000000 +0200
++++ mpg123-1.12.1-new/src/libmpg123/id3.c 2010-07-07 23:51:50.000000000 +0200
+@@ -9,6 +9,8 @@
+ #include "mpg123lib_intern.h"
+ #include "id3.h"
+ #include "debug.h"
++#include "rccpatch.h"
++
+
+ #ifndef NO_ID3V2 /* Only the main parsing routine will always be there. */
+
+@@ -829,6 +831,15 @@
+ size_t length = l;
+ size_t i;
+ unsigned char *p;
++ char *ctitle;
++
++ ctitle = mpg123_rcc_recode(s, l, &i);
++ if (ctitle) {
++ convert_utf8(sb, ctitle, i, 0);
++ free(ctitle);
++ return;
++ }
++
+ /* determine real length, a latin1 character can at most take 2 in UTF8 */
+ for(i=0; i<l; ++i)
+ if(s[i] >= 0x80) ++length;
+diff -dPNur mpg123-1.12.1/src/libmpg123/Makefile.am mpg123-1.12.1-new/src/libmpg123/Makefile.am
+--- mpg123-1.12.1/src/libmpg123/Makefile.am 2010-03-31 10:27:35.000000000 +0200
++++ mpg123-1.12.1-new/src/libmpg123/Makefile.am 2010-07-07 23:44:57.000000000 +0200
+@@ -29,6 +29,8 @@
+ libmpg123_la_DEPENDENCIES = @DECODER_LOBJ@ @LFS_LOBJ@
+
+ libmpg123_la_SOURCES = \
++ rccpatch.c \
++ rccpatch.h \
+ compat.c \
+ compat.h \
+ parse.c \
+diff -dPNur mpg123-1.12.1/src/libmpg123/rccpatch.c mpg123-1.12.1-new/src/libmpg123/rccpatch.c
+--- mpg123-1.12.1/src/libmpg123/rccpatch.c 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-1.12.1-new/src/libmpg123/rccpatch.c 2010-07-07 23:55:59.000000000 +0200
+@@ -0,0 +1,76 @@
++#include <string.h>
++#include <librcc.h>
++#include "mpg123.h"
++
++#define ID3_CLASS 0
++#define UTF_CLASS 1
++#define OUT_CLASS 2
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, NULL, NULL, "Output Encoding", 0 },
++ { NULL }
++};
++
++static int rcc_initialized = 0;
++
++void mpg123_rcc_free() {
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++}
++
++void mpg123_rcc_init() {
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++}
++
++static void mpg123_rcc_try_init() {
++ if (!rcc_initialized) {
++ mpg123_rcc_init();
++ if (rcc_initialized) atexit(mpg123_rcc_free);
++ }
++}
++
++
++char *mpg123_rcc_recode(const char *str, size_t len, size_t *rlen) {
++ char *res;
++ mpg123_rcc_try_init();
++ return rccSizedRecode(NULL, ID3_CLASS, UTF_CLASS, str, len, rlen);
++}
++
++static void mpg123_rcc_recode_string(mpg123_string *str, rcc_class_id from, rcc_class_id to) {
++ size_t size;
++ char *res;
++
++ if ((!str)||(str->fill<2)) return;
++
++ mpg123_rcc_try_init();
++
++ res = rccSizedRecode(NULL, from, to, str->p, str->fill - 1, &size);
++ if (res) {
++ if (size+1>str->size) {
++ if (!mpg123_resize_string(str, size + 1)) {
++ // allocation failed
++ free(res);
++ return;
++ }
++ }
++ strncpy(str->p, res, size + 1);
++ str->fill = size + 1;
++ free(res);
++ }
++}
++
++void mpg123_rcc_recode_utf_string(mpg123_string *str) {
++ mpg123_rcc_recode_string(str, UTF_CLASS, OUT_CLASS);
++}
++
++void mpg123_rcc_recode_latin_string(mpg123_string *str) {
++ mpg123_rcc_recode_string(str, ID3_CLASS, OUT_CLASS);
++}
+diff -dPNur mpg123-1.12.1/src/libmpg123/rccpatch.h mpg123-1.12.1-new/src/libmpg123/rccpatch.h
+--- mpg123-1.12.1/src/libmpg123/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-1.12.1-new/src/libmpg123/rccpatch.h 2010-07-07 23:44:57.000000000 +0200
+@@ -0,0 +1,5 @@
++void mpg123_rcc_free();
++void mpg123_rcc_init();
++char *mpg123_rcc_recode(const char *str, size_t len, size_t *rlen);
++void mpg123_rcc_recode_utf_string(mpg123_string *str);
++void mpg123_rcc_recode_latin_string(mpg123_string *str);
+diff -dPNur mpg123-1.12.1/src/Makefile.am mpg123-1.12.1-new/src/Makefile.am
+--- mpg123-1.12.1/src/Makefile.am 2010-03-31 10:27:36.000000000 +0200
++++ mpg123-1.12.1-new/src/Makefile.am 2010-07-07 23:46:10.000000000 +0200
+@@ -5,10 +5,10 @@
+ ## initially written by Nicholas J. Humfrey
+
+ AM_CPPFLAGS = -DPKGLIBDIR="\"$(pkglibdir)\""
+-mpg123_LDADD = $(LIBLTDL) libmpg123/libmpg123.la @MODULE_OBJ@ @OUTPUT_OBJ@ @OUTPUT_LIBS@
++mpg123_LDADD = $(LIBLTDL) libmpg123/libmpg123.la @MODULE_OBJ@ @OUTPUT_OBJ@ @OUTPUT_LIBS@ @LIBRCC_LIBS@
+ mpg123_LDFLAGS = @EXEC_LT_LDFLAGS@ @OUTPUT_LDFLAGS@
+ # Just mpg123_INCLUDES has no effect on build! Trying that before reverting to AM_CPPFLAGS.
+-INCLUDES = $(LTDLINCL) -I$(top_builddir)/src/libmpg123 -I$(top_srcdir)/src/libmpg123
++INCLUDES = $(LTDLINCL) -I$(top_builddir)/src/libmpg123 -I$(top_srcdir)/src/libmpg123 @LIBRCC_INCLUDES@
+ # libltdl is not mentioned here... it's not that trivial
+ mpg123_DEPENDENCIES = @OUTPUT_OBJ@ @MODULE_OBJ@ libmpg123/libmpg123.la
+
+diff -dPNur mpg123-1.12.1/src/metaprint.c mpg123-1.12.1-new/src/metaprint.c
+--- mpg123-1.12.1/src/metaprint.c 2010-03-31 10:27:36.000000000 +0200
++++ mpg123-1.12.1-new/src/metaprint.c 2010-07-07 23:54:21.000000000 +0200
+@@ -17,7 +17,11 @@
+ if(source == NULL) return;
+
+ if(utf8env) mpg123_copy_string(source, dest);
+- else utf8_ascii(dest, source);
++ else {
++ mpg123_copy_string(source, dest);
++ mpg123_rcc_recode_utf_string(dest);
++// utf8_ascii(dest, source);
++ }
+ }
+
+ /* print tags... limiting the UTF-8 to ASCII */
+@@ -53,6 +57,7 @@
+ strncpy(tag[TITLE].p,v1->title,30);
+ tag[TITLE].p[30] = 0;
+ tag[TITLE].fill = strlen(tag[TITLE].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[TITLE]);
+ }
+ }
+ if(!tag[ARTIST].fill)
+@@ -62,6 +67,7 @@
+ strncpy(tag[ARTIST].p,v1->artist,30);
+ tag[ARTIST].p[30] = 0;
+ tag[ARTIST].fill = strlen(tag[ARTIST].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[ARTIST]);
+ }
+ }
+ if(!tag[ALBUM].fill)
+@@ -71,6 +77,7 @@
+ strncpy(tag[ALBUM].p,v1->album,30);
+ tag[ALBUM].p[30] = 0;
+ tag[ALBUM].fill = strlen(tag[ALBUM].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[ALBUM]);
+ }
+ }
+ if(!tag[COMMENT].fill)
+@@ -80,6 +87,7 @@
+ strncpy(tag[COMMENT].p,v1->comment,30);
+ tag[COMMENT].p[30] = 0;
+ tag[COMMENT].fill = strlen(tag[COMMENT].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[COMMENT]);
+ }
+ }
+ if(!tag[YEAR].fill)
+diff -dPNur mpg123-1.12.1/src/mpg123.c mpg123-1.12.1-new/src/mpg123.c
+--- mpg123-1.12.1/src/mpg123.c 2010-03-31 10:27:36.000000000 +0200
++++ mpg123-1.12.1-new/src/mpg123.c 2010-07-07 23:52:58.000000000 +0200
+@@ -10,6 +10,7 @@
+ #include "mpg123app.h"
+ #include "mpg123.h"
+ #include "local.h"
++#include "rccpatch.h"
+
+ #ifdef HAVE_SYS_WAIT_H
+ #include <sys/wait.h>
+@@ -973,6 +974,8 @@
+ if(param.term_ctrl)
+ term_init();
+ #endif
++
++ mpg123_rcc_init();
+ while ((fname = get_next_file()))
+ {
+ char *dirname, *filename;
+@@ -1132,6 +1135,8 @@
+ #endif
+ }
+ } /* end of loop over input files */
++ mpg123_rcc_free();
++
+ /* Ensure we played everything. */
+ if(param.smooth && param.usebuffer)
+ {
diff --git a/patches/mpg123/mpg123-ds-rcc173.patch b/patches/mpg123/mpg123-ds-rcc173.patch
new file mode 100644
index 0000000..ae814ff
--- /dev/null
+++ b/patches/mpg123/mpg123-ds-rcc173.patch
@@ -0,0 +1,271 @@
+diff -dPNur mpg123-1.7.3/configure.ac mpg123-1.7.3-rusxmms/configure.ac
+--- mpg123-1.7.3/configure.ac 2009-04-27 09:02:40.000000000 +0200
++++ mpg123-1.7.3-rusxmms/configure.ac 2009-06-13 23:22:17.000000000 +0200
+@@ -759,6 +759,21 @@
+ AC_CHECK_LIB([m], [sqrt])
+ AC_CHECK_LIB([mx], [powf])
+
++# LibRCC
++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)
++
+ # attempt to make the signal stuff work... also with GENERIC - later
+ #if test x"$ac_cv_header_sys_signal_h" = xyes; then
+ # AC_CHECK_FUNCS( sigemptyset sigaddset sigprocmask sigaction )
+diff -dPNur mpg123-1.7.3/src/libmpg123/id3.c mpg123-1.7.3-rusxmms/src/libmpg123/id3.c
+--- mpg123-1.7.3/src/libmpg123/id3.c 2009-04-27 09:02:12.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/libmpg123/id3.c 2009-06-14 00:34:23.000000000 +0200
+@@ -9,6 +9,8 @@
+ #include "mpg123lib_intern.h"
+ #include "id3.h"
+ #include "debug.h"
++#include "rccpatch.h"
++
+
+ #ifndef NO_ID3V2 /* Only the main parsing routine will always be there. */
+
+@@ -774,6 +776,15 @@
+ size_t length = l;
+ size_t i;
+ unsigned char *p;
++ char *ctitle;
++
++ ctitle = mpg123_rcc_recode(s, l, &i);
++ if (ctitle) {
++ convert_utf8(sb, ctitle, i);
++ free(ctitle);
++ return;
++ }
++
+ /* determine real length, a latin1 character can at most take 2 in UTF8 */
+ for(i=0; i<l; ++i)
+ if(s[i] >= 0x80) ++length;
+diff -dPNur mpg123-1.7.3/src/libmpg123/libmpg123.sym mpg123-1.7.3-rusxmms/src/libmpg123/libmpg123.sym
+--- mpg123-1.7.3/src/libmpg123/libmpg123.sym 2009-04-27 09:07:20.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/libmpg123/libmpg123.sym 2009-06-14 01:53:25.000000000 +0200
+@@ -74,3 +74,8 @@
+ mpg123_position
+ mpg123_length
+ mpg123_set_filesize
++mpg123_rcc_free
++mpg123_rcc_init
++mpg123_rcc_recode
++mpg123_rcc_recode_utf_string
++mpg123_rcc_recode_latin_string
+diff -dPNur mpg123-1.7.3/src/libmpg123/libmpg123.sym.in mpg123-1.7.3-rusxmms/src/libmpg123/libmpg123.sym.in
+--- mpg123-1.7.3/src/libmpg123/libmpg123.sym.in 2009-04-27 09:02:12.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/libmpg123/libmpg123.sym.in 2009-06-14 01:51:45.000000000 +0200
+@@ -74,3 +74,8 @@
+ mpg123_position@LARGEFILE_SUFFIX@
+ mpg123_length@LARGEFILE_SUFFIX@
+ mpg123_set_filesize@LARGEFILE_SUFFIX@
++mpg123_rcc_free
++mpg123_rcc_init
++mpg123_rcc_recode
++mpg123_rcc_recode_utf_string
++mpg123_rcc_recode_latin_string
+diff -dPNur mpg123-1.7.3/src/libmpg123/Makefile.am mpg123-1.7.3-rusxmms/src/libmpg123/Makefile.am
+--- mpg123-1.7.3/src/libmpg123/Makefile.am 2009-04-27 09:02:12.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/libmpg123/Makefile.am 2009-06-14 00:10:34.000000000 +0200
+@@ -31,6 +31,8 @@
+ libmpg123_la_DEPENDENCIES = @DECODER_LOBJ@ libmpg123.sym
+
+ libmpg123_la_SOURCES = \
++ rccpatch.c \
++ rccpatch.h \
+ compat.c \
+ compat.h \
+ parse.c \
+diff -dPNur mpg123-1.7.3/src/libmpg123/rccpatch.c mpg123-1.7.3-rusxmms/src/libmpg123/rccpatch.c
+--- mpg123-1.7.3/src/libmpg123/rccpatch.c 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-1.7.3-rusxmms/src/libmpg123/rccpatch.c 2009-06-14 01:54:37.000000000 +0200
+@@ -0,0 +1,76 @@
++#include <string.h>
++#include <librcc.h>
++#include "mpg123.h"
++
++#define ID3_CLASS 0
++#define UTF_CLASS 1
++#define OUT_CLASS 2
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "utf", RCC_CLASS_KNOWN, "UTF-8", NULL, "Unicode Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, NULL, NULL, "Output Encoding", 0 },
++ { NULL }
++};
++
++static int rcc_initialized = 0;
++
++void mpg123_rcc_free() {
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++}
++
++void mpg123_rcc_init() {
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++}
++
++static void mpg123_rcc_try_init() {
++ if (!rcc_initialized) {
++ mpg123_rcc_init();
++ if (rcc_initialized) atexit(mpg123_rcc_free);
++ }
++}
++
++
++char *mpg123_rcc_recode(const char *str, size_t len, size_t *rlen) {
++ char *res;
++ mpg123_rcc_try_init();
++ return rccSizedRecode(NULL, ID3_CLASS, UTF_CLASS, str, len, rlen);
++}
++
++static void mpg123_rcc_recode_string(mpg123_string *str, rcc_class_id from, rcc_class_id to) {
++ size_t size;
++ char *res;
++
++ if ((!str)||(str->fill<2)) return;
++
++ mpg123_rcc_try_init();
++
++ res = rccSizedRecode(NULL, from, to, str->p, str->fill - 1, &size);
++ if (res) {
++ if (size+1>str->size) {
++ if (!mpg123_resize_string(str, size + 1)) {
++ // allocation failed
++ free(res);
++ return;
++ }
++ }
++ strncpy(str->p, res, size + 1);
++ str->fill = size + 1;
++ free(res);
++ }
++}
++
++void mpg123_rcc_recode_utf_string(mpg123_string *str) {
++ mpg123_rcc_recode_string(str, UTF_CLASS, OUT_CLASS);
++}
++
++void mpg123_rcc_recode_latin_string(mpg123_string *str) {
++ mpg123_rcc_recode_string(str, ID3_CLASS, OUT_CLASS);
++}
+diff -dPNur mpg123-1.7.3/src/libmpg123/rccpatch.h mpg123-1.7.3-rusxmms/src/libmpg123/rccpatch.h
+--- mpg123-1.7.3/src/libmpg123/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-1.7.3-rusxmms/src/libmpg123/rccpatch.h 2009-06-14 01:51:21.000000000 +0200
+@@ -0,0 +1,5 @@
++void mpg123_rcc_free();
++void mpg123_rcc_init();
++char *mpg123_rcc_recode(const char *str, size_t len, size_t *rlen);
++void mpg123_rcc_recode_utf_string(mpg123_string *str);
++void mpg123_rcc_recode_latin_string(mpg123_string *str);
+diff -dPNur mpg123-1.7.3/src/Makefile.am mpg123-1.7.3-rusxmms/src/Makefile.am
+--- mpg123-1.7.3/src/Makefile.am 2009-04-27 09:02:12.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/Makefile.am 2009-06-14 00:10:22.000000000 +0200
+@@ -5,10 +5,10 @@
+ ## initially written by Nicholas J. Humfrey
+
+ AM_CPPFLAGS = -DPKGLIBDIR="\"$(pkglibdir)\""
+-mpg123_LDADD = $(LIBLTDL) libmpg123/libmpg123.la @MODULE_OBJ@ @OUTPUT_OBJ@ @OUTPUT_LIBS@
++mpg123_LDADD = $(LIBLTDL) libmpg123/libmpg123.la @MODULE_OBJ@ @OUTPUT_OBJ@ @OUTPUT_LIBS@ @LIBRCC_LIBS@
+ mpg123_LDFLAGS = @LT_LDFLAGS@ @OUTPUT_LDFLAGS@
+ # Just mpg123_INCLUDES has no effect on build! Trying that before reverting to AM_CPPFLAGS.
+-INCLUDES = $(LTDLINCL) -I$(top_builddir)/src/libmpg123 -I$(top_srcdir)/src/libmpg123
++INCLUDES = $(LTDLINCL) -I$(top_builddir)/src/libmpg123 -I$(top_srcdir)/src/libmpg123 @LIBRCC_INCLUDES@
+ # libltdl is not mentioned here... it's not that trivial
+ mpg123_DEPENDENCIES = @OUTPUT_OBJ@ @MODULE_OBJ@ libmpg123/libmpg123.la
+
+diff -dPNur mpg123-1.7.3/src/metaprint.c mpg123-1.7.3-rusxmms/src/metaprint.c
+--- mpg123-1.7.3/src/metaprint.c 2009-04-27 09:02:12.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/metaprint.c 2009-06-14 01:59:09.000000000 +0200
+@@ -17,7 +17,11 @@
+ if(source == NULL) return;
+
+ if(utf8env) mpg123_copy_string(source, dest);
+- else utf8_ascii(dest, source);
++ else {
++ mpg123_copy_string(source, dest);
++ mpg123_rcc_recode_utf_string(dest);
++// utf8_ascii(dest, source);
++ }
+ }
+
+ /* print tags... limiting the UTF-8 to ASCII */
+@@ -53,6 +57,7 @@
+ strncpy(tag[TITLE].p,v1->title,30);
+ tag[TITLE].p[30] = 0;
+ tag[TITLE].fill = strlen(tag[TITLE].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[TITLE]);
+ }
+ }
+ if(!tag[ARTIST].fill)
+@@ -62,6 +67,7 @@
+ strncpy(tag[ARTIST].p,v1->artist,30);
+ tag[ARTIST].p[30] = 0;
+ tag[ARTIST].fill = strlen(tag[ARTIST].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[ARTIST]);
+ }
+ }
+ if(!tag[ALBUM].fill)
+@@ -71,6 +77,7 @@
+ strncpy(tag[ALBUM].p,v1->album,30);
+ tag[ALBUM].p[30] = 0;
+ tag[ALBUM].fill = strlen(tag[ALBUM].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[ALBUM]);
+ }
+ }
+ if(!tag[COMMENT].fill)
+@@ -80,6 +87,7 @@
+ strncpy(tag[COMMENT].p,v1->comment,30);
+ tag[COMMENT].p[30] = 0;
+ tag[COMMENT].fill = strlen(tag[COMMENT].p) + 1;
++ mpg123_rcc_recode_latin_string(&tag[COMMENT]);
+ }
+ }
+ if(!tag[YEAR].fill)
+diff -dPNur mpg123-1.7.3/src/mpg123.c mpg123-1.7.3-rusxmms/src/mpg123.c
+--- mpg123-1.7.3/src/mpg123.c 2009-04-27 09:02:12.000000000 +0200
++++ mpg123-1.7.3-rusxmms/src/mpg123.c 2009-06-14 00:35:14.000000000 +0200
+@@ -10,6 +10,7 @@
+ #include "mpg123app.h"
+ #include "mpg123.h"
+ #include "local.h"
++#include "rccpatch.h"
+
+ #ifdef HAVE_SYS_WAIT_H
+ #include <sys/wait.h>
+@@ -893,6 +894,8 @@
+ if(param.term_ctrl)
+ term_init();
+ #endif
++
++ mpg123_rcc_init();
+ while ((fname = get_next_file()))
+ {
+ char *dirname, *filename;
+@@ -1038,6 +1041,8 @@
+ #endif
+ }
+ } /* end of loop over input files */
++ mpg123_rcc_free();
++
+ /* Ensure we played everything. */
+ if(param.smooth && param.usebuffer)
+ {
diff --git a/patches/mpg123/mpg123-ds-rcc65.patch b/patches/mpg123/mpg123-ds-rcc65.patch
new file mode 100644
index 0000000..41a4d33
--- /dev/null
+++ b/patches/mpg123/mpg123-ds-rcc65.patch
@@ -0,0 +1,240 @@
+diff -dPNur mpg123-0.65/configure.ac mpg123-0.65-new/configure.ac
+--- mpg123-0.65/configure.ac 2007-02-07 10:24:33.000000000 +0100
++++ mpg123-0.65-new/configure.ac 2007-04-15 13:36:52.000000000 +0200
+@@ -137,6 +137,21 @@
+ AC_CHECK_LIB([m], [sqrt])
+ AC_CHECK_LIB([mx], [powf])
+
++# LibRCC
++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)
++
+ # Check for JACK
+ PKG_CHECK_MODULES(JACK, jack, HAVE_JACK=yes, HAVE_JACK=no)
+
+diff -dPNur mpg123-0.65/src/id3.c mpg123-0.65-new/src/id3.c
+--- mpg123-0.65/src/id3.c 2007-02-07 10:24:33.000000000 +0100
++++ mpg123-0.65-new/src/id3.c 2007-04-15 13:26:06.000000000 +0200
+@@ -6,6 +6,7 @@
+ #include "stringbuf.h"
+ #include "genre.h"
+ #include "id3.h"
++#include "rccpatch.h"
+
+ struct taginfo
+ {
+@@ -499,6 +500,8 @@
+ void print_id3_tag(unsigned char *id3v1buf)
+ {
+ char genre_from_v1 = 0;
++ char *ctitle, *cartist, *calbum, *ccomment;
++
+ if(!(id3.version || id3v1buf)) return;
+ if(id3v1buf != NULL)
+ {
+@@ -688,17 +691,26 @@
+ free_stringbuf(&tmp);
+ }
+
++ if (id3.title.fill) ctitle = rccPatchRecode(id3.title.p);
++ else ctitle = NULL;
++ if (id3.artist.fill) cartist = rccPatchRecode(id3.artist.p);
++ else cartist = NULL;
++ if (id3.album.fill) calbum = rccPatchRecode(id3.album.p);
++ else calbum = NULL;
++ if (id3.comment.fill) ccomment = rccPatchRecode(id3.comment.p);
++ else ccomment = NULL;
++
+ if(param.long_id3)
+ {
+ fprintf(stderr,"\n");
+ /* print id3v2 */
+ /* dammed, I use pointers as bool again! It's so convenient... */
+- fprintf(stderr,"\tTitle: %s\n", id3.title.fill ? id3.title.p : "");
+- fprintf(stderr,"\tArtist: %s\n", id3.artist.fill ? id3.artist.p : "");
+- fprintf(stderr,"\tAlbum: %s\n", id3.album.fill ? id3.album.p : "");
++ fprintf(stderr,"\tTitle: %s\n", ctitle?ctitle:(id3.title.fill ? id3.title.p : ""));
++ fprintf(stderr,"\tArtist: %s\n", cartist?cartist:(id3.artist.fill ? id3.artist.p : ""));
++ fprintf(stderr,"\tAlbum: %s\n", calbum?calbum:(id3.album.fill ? id3.album.p : ""));
+ fprintf(stderr,"\tYear: %s\n", id3.year.fill ? id3.year.p : "");
+ fprintf(stderr,"\tGenre: %s\n", id3.genre.fill ? id3.genre.p : "");
+- fprintf(stderr,"\tComment: %s\n", id3.comment.fill ? id3.comment.p : "");
++ fprintf(stderr,"\tComment: %s\n", ccomment?ccomment:(id3.comment.fill ? id3.comment.p : ""));
+ fprintf(stderr,"\n");
+ }
+ else
+@@ -708,23 +720,23 @@
+ /* one _could_ circumvent the strlen calls... */
+ if(id3.title.fill && id3.artist.fill && strlen(id3.title.p) <= 30 && strlen(id3.title.p) <= 30)
+ {
+- fprintf(stderr,"Title: %-30s Artist: %s\n",id3.title.p,id3.artist.p);
++ fprintf(stderr,"Title: %-30s Artist: %s\n",ctitle?ctitle:id3.title.p,cartist?cartist:id3.artist.p);
+ }
+ else
+ {
+- if(id3.title.fill) fprintf(stderr,"Title: %s\n", id3.title.p);
+- if(id3.artist.fill) fprintf(stderr,"Artist: %s\n", id3.artist.p);
++ if(id3.title.fill) fprintf(stderr,"Title: %s\n", ctitle?ctitle:id3.title.p);
++ if(id3.artist.fill) fprintf(stderr,"Artist: %s\n", cartist?cartist:id3.artist.p);
+ }
+ if (id3.comment.fill && id3.album.fill && strlen(id3.comment.p) <= 30 && strlen(id3.album.p) <= 30)
+ {
+- fprintf(stderr,"Comment: %-30s Album: %s\n",id3.comment.p,id3.album.p);
++ fprintf(stderr,"Comment: %-30s Album: %s\n",ccomment?ccomment:id3.comment.p,calbum?calbum:id3.album.p);
+ }
+ else
+ {
+ if (id3.comment.fill)
+- fprintf(stderr,"Comment: %s\n", id3.comment.p);
++ fprintf(stderr,"Comment: %s\n", ccomment?ccomment:id3.comment.p);
+ if (id3.album.fill)
+- fprintf(stderr,"Album: %s\n", id3.album.p);
++ fprintf(stderr,"Album: %s\n", calbum?calbum:id3.album.p);
+ }
+ if (id3.year.fill && id3.genre.fill && strlen(id3.year.p) <= 30 && strlen(id3.genre.p) <= 30)
+ {
+@@ -738,6 +750,11 @@
+ fprintf(stderr,"Genre: %s\n", id3.genre.p);
+ }
+ }
++
++ if (ctitle) free(ctitle);
++ if (cartist) free(cartist);
++ if (calbum) free(calbum);
++ if (ccomment) free(ccomment);
+ }
+
+ /*
+diff -dPNur mpg123-0.65/src/Makefile.am mpg123-0.65-new/src/Makefile.am
+--- mpg123-0.65/src/Makefile.am 2007-02-07 10:24:33.000000000 +0100
++++ mpg123-0.65-new/src/Makefile.am 2007-04-15 13:38:44.000000000 +0200
+@@ -4,8 +4,8 @@
+ ## see COPYING and AUTHORS files in distribution or http://mpg123.de
+ ## initially written by Nicholas J. Humfrey
+
+-AM_CFLAGS = @AUDIO_CFLAGS@
+-AM_LDFLAGS = @AUDIO_LIBS@
++AM_CFLAGS = @AUDIO_CFLAGS@ @LIBRCC_INCLUDES@
++AM_LDFLAGS = @AUDIO_LIBS@ @LIBRCC_LIBS@
+ mpg123_LDADD = @AUDIO_OBJ@ @CPU_TYPE_LIB@
+ mpg123_DEPENDENCIES = @AUDIO_OBJ@ @CPU_TYPE_LIB@
+
+@@ -14,6 +14,8 @@
+
+ bin_PROGRAMS = mpg123
+ mpg123_SOURCES = \
++ rccpatch.c \
++ rccpatch.h \
+ audio.c \
+ audio.h \
+ buffer.c \
+diff -dPNur mpg123-0.65/src/mpg123.c mpg123-0.65-new/src/mpg123.c
+--- mpg123-0.65/src/mpg123.c 2007-02-07 10:24:33.000000000 +0100
++++ mpg123-0.65-new/src/mpg123.c 2007-04-15 13:30:42.000000000 +0200
+@@ -35,6 +35,7 @@
+ #include "layer3.h"
+ #endif
+ #include "playlist.h"
++#include "rccpatch.h"
+ #include "id3.h"
+ #include "icy.h"
+
+@@ -814,15 +815,18 @@
+
+ if(param.remote) {
+ int ret;
++ rccPatchInit();
+ init_id3();
+ init_icy();
+ ret = control_generic(&fr);
+ clear_icy();
+ exit_id3();
++ rccPatchFree();
+ safe_exit(ret);
+ }
+ #endif
+
++ rccPatchInit();
+ init_icy();
+ init_id3(); /* prepare id3 memory */
+ while ((fname = get_next_file())) {
+@@ -851,7 +855,7 @@
+ }
+ }
+ #endif
+-
++
+ }
+
+ #if !defined(WIN32) && !defined(GENERIC)
+@@ -1031,6 +1035,7 @@
+ } /* end of loop over input files */
+ clear_icy();
+ exit_id3(); /* free id3 memory */
++ rccPatchFree();
+ #ifndef NOXFERMEM
+ if (param.usebuffer) {
+ buffer_end();
+diff -dPNur mpg123-0.65/src/rccpatch.c mpg123-0.65-new/src/rccpatch.c
+--- mpg123-0.65/src/rccpatch.c 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-0.65-new/src/rccpatch.c 2007-04-15 13:13:09.000000000 +0200
+@@ -0,0 +1,40 @@
++#include <librcc.h>
++
++#define ID3_CLASS 0
++#define OUT_CLASS 1
++static rcc_class classes[] = {
++ { "id3", RCC_CLASS_STANDARD, NULL, NULL, "ID3 Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, NULL, NULL, "Output Encoding", 0 },
++ { NULL }
++};
++
++static int rcc_initialized = 0;
++
++void rccPatchFree() {
++ if (rcc_initialized) {
++ rccFree();
++ rcc_initialized = 0;
++ }
++}
++
++void rccPatchInit() {
++ if (rcc_initialized) return;
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "xmms");
++ rccInitDb4(NULL, NULL, 0);
++ rcc_initialized = 1;
++}
++
++static void rccPatchTryInit() {
++ if (!rcc_initialized) {
++ rccPatchInit();
++ if (rcc_initialized) atexit(rccPatchFree);
++ }
++}
++
++char *rccPatchRecode(const char *str) {
++ char *res;
++ rccPatchTryInit();
++ return rccRecode(NULL, ID3_CLASS, OUT_CLASS, str);
++}
+diff -dPNur mpg123-0.65/src/rccpatch.h mpg123-0.65-new/src/rccpatch.h
+--- mpg123-0.65/src/rccpatch.h 1970-01-01 01:00:00.000000000 +0100
++++ mpg123-0.65-new/src/rccpatch.h 2007-04-15 13:13:09.000000000 +0200
+@@ -0,0 +1,4 @@
++void rccPatchFree();
++void rccPatchInit();
++char *rccPatchRecode(const char *str);
++
diff --git a/patches/p7zip/README b/patches/p7zip/README
new file mode 100644
index 0000000..fe8ae08
--- /dev/null
+++ b/patches/p7zip/README
@@ -0,0 +1,13 @@
+Difference between 'rusxmms' and 'rusxmms-full' patches is following. The full patche besides makefile.machine fixes all
+other architecure-oss specific make files. The 'rusxmms' patch does not. However, you could execute following commands
+to have all makefiles adjusted.
+
+find . -maxdepth 1 -name "makefile.linux*" -print0 | xargs -0 sed -i -e "s/LOCAL_LIBS=-lpthread/LOCAL_LIBS=-lpthread -lrcc/"
+find . -maxdepth 1 -name "makefile.machine" -print0 | xargs -0 sed -i -e "s/LOCAL_LIBS=-lpthread/LOCAL_LIBS=-lpthread -lrcc/"
+
+
+Configuration
+=============
+ - The patch uses "zip" configuration of RCC. This means settings could be
+ altered using "rcc-gtk2-config zip".
+ - ZIP OEM / Output - encodings are important for patch.
diff --git a/patches/p7zip/p7zip_4.44-ds-rusxmms-full.patch b/patches/p7zip/p7zip_4.44-ds-rusxmms-full.patch
new file mode 100644
index 0000000..98e7855
--- /dev/null
+++ b/patches/p7zip/p7zip_4.44-ds-rusxmms-full.patch
@@ -0,0 +1,314 @@
+diff -dPNur p7zip_4.44-old/C/rccrecode.c p7zip_4.44/C/rccrecode.c
+--- p7zip_4.44-old/C/rccrecode.c 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.44/C/rccrecode.c 2007-04-14 19:47:03.000000000 +0200
+@@ -0,0 +1,69 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip_4.44-old/C/rccrecode.h p7zip_4.44/C/rccrecode.h
+--- p7zip_4.44-old/C/rccrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.44/C/rccrecode.h 2007-04-14 19:34:20.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip_4.44-old/CPP/7zip/Archive/Zip/makefile p7zip_4.44/CPP/7zip/Archive/Zip/makefile
+--- p7zip_4.44-old/CPP/7zip/Archive/Zip/makefile 2007-01-23 21:29:41.000000000 +0100
++++ p7zip_4.44/CPP/7zip/Archive/Zip/makefile 2007-04-14 18:36:44.000000000 +0200
+@@ -13,6 +13,7 @@
+ LIBS=$(LOCAL_LIBS_DLL)
+
+ OBJS = \
++../../../../C/rccrecode.o \
+ ../../../Common/MyWindows.o \
+ ../../../Common/Vector.o\
+ ../../../Common/Alloc.o\
+diff -dPNur p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip_4.44/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipIn.cpp 2007-01-20 18:06:58.000000000 +0100
++++ p7zip_4.44/CPP/7zip/Archive/Zip/ZipIn.cpp 2007-04-14 19:34:59.000000000 +0200
+@@ -9,11 +9,22 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
++
++CInArchive::CInArchive() {
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive() {
++ rcc_free(rccctx);
++}
++
+
+ // static const char kEndOfString = '\0';
+-
++
+ bool CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
+ {
+ m_Stream = inStream;
+@@ -179,10 +190,18 @@
+
+ AString CInArchive::ReadFileName(UInt32 nameSize)
+ {
++ char *rccrec;
+ if (nameSize == 0)
+ return AString();
+ SafeReadBytes(m_NameBuffer.GetBuffer(nameSize), nameSize);
+ m_NameBuffer.ReleaseBuffer(nameSize);
++
++ rccrec = rcc_read(rccctx, (LPCSTR)m_NameBuffer, 0);
++ if (rccrec) {
++ m_NameBuffer = rccrec;
++ free(rccrec);
++ }
++
+ return m_NameBuffer;
+ }
+
+diff -dPNur p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipIn.h p7zip_4.44/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipIn.h 2007-01-20 18:06:28.000000000 +0100
++++ p7zip_4.44/CPP/7zip/Archive/Zip/ZipIn.h 2007-04-14 19:05:31.000000000 +0200
+@@ -104,6 +104,10 @@
+ bool SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
++
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
+ };
+
+ }}
+diff -dPNur p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip_4.44/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipOut.cpp 2007-01-20 18:06:57.000000000 +0100
++++ p7zip_4.44/CPP/7zip/Archive/Zip/ZipOut.cpp 2007-04-14 19:44:44.000000000 +0200
+@@ -8,9 +8,19 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ m_Stream = outStream;
+@@ -104,6 +114,8 @@
+
+ HRESULT COutArchive::WriteLocalHeader(const CLocalItem &item)
+ {
++ char *rccrec;
++
+ m_Stream->Seek(m_BasePosition, STREAM_SEEK_SET, NULL);
+
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+@@ -124,6 +136,12 @@
+ return E_FAIL;
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("%u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+@@ -147,6 +165,8 @@
+
+ void COutArchive::WriteCentralHeader(const CItem &item)
+ {
++ char *rccrec;
++
+ m_Stream->Seek(m_BasePosition, STREAM_SEEK_SET, NULL);
+
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+@@ -175,6 +195,13 @@
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
++
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("C: %u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+diff -dPNur p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipOut.h p7zip_4.44/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip_4.44-old/CPP/7zip/Archive/Zip/ZipOut.h 2007-01-20 18:06:29.000000000 +0100
++++ p7zip_4.44/CPP/7zip/Archive/Zip/ZipOut.h 2007-04-14 19:10:12.000000000 +0200
+@@ -44,6 +44,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++
+ };
+
+ }}
+diff -dPNur p7zip_4.44-old/CPP/7zip/Bundles/Alone/makefile p7zip_4.44/CPP/7zip/Bundles/Alone/makefile
+--- p7zip_4.44-old/CPP/7zip/Bundles/Alone/makefile 2007-01-23 21:29:43.000000000 +0100
++++ p7zip_4.44/CPP/7zip/Bundles/Alone/makefile 2007-04-14 18:52:31.000000000 +0200
+@@ -41,6 +41,7 @@
+ $(MY_HOME)/mySplitCommandLine.o
+
+ OBJS=\
++../../../../C/rccrecode.o \
+ ../../../Common/MyWindows.o \
+ 7zAES.o \
+ 7zCompressionMode.o \
+diff -dPNur p7zip_4.44-old/makefile.linux_amd64 p7zip_4.44/makefile.linux_amd64
+--- p7zip_4.44-old/makefile.linux_amd64 2007-04-14 15:37:39.000000000 +0200
++++ p7zip_4.44/makefile.linux_amd64 2007-04-14 18:50:13.000000000 +0200
+@@ -11,6 +11,6 @@
+ CC=x86_64-pc-linux-gnu-gcc $(ALLFLAGS)
+ LINK_SHARED=-shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+diff -dPNur p7zip_4.44-old/makefile.linux_gcc_2.95_no_need_for_libstdc p7zip_4.44/makefile.linux_gcc_2.95_no_need_for_libstdc
+--- p7zip_4.44-old/makefile.linux_gcc_2.95_no_need_for_libstdc 2007-04-14 15:37:39.000000000 +0200
++++ p7zip_4.44/makefile.linux_gcc_2.95_no_need_for_libstdc 2007-04-14 18:51:02.000000000 +0200
+@@ -10,6 +10,6 @@
+ CC=x86_64-pc-linux-gnu-gcc $(ALLFLAGS)
+ LINK_SHARED=-shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+diff -dPNur p7zip_4.44-old/makefile.linux_x86_ppc_alpha p7zip_4.44/makefile.linux_x86_ppc_alpha
+--- p7zip_4.44-old/makefile.linux_x86_ppc_alpha 2007-04-14 15:37:39.000000000 +0200
++++ p7zip_4.44/makefile.linux_x86_ppc_alpha 2007-04-14 18:51:15.000000000 +0200
+@@ -14,6 +14,6 @@
+ CC=x86_64-pc-linux-gnu-gcc $(ALLFLAGS)
+ LINK_SHARED=-shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+diff -dPNur p7zip_4.44-old/makefile.linux_x86_ppc_alpha__gcc_4.X p7zip_4.44/makefile.linux_x86_ppc_alpha__gcc_4.X
+--- p7zip_4.44-old/makefile.linux_x86_ppc_alpha__gcc_4.X 2007-04-14 15:37:39.000000000 +0200
++++ p7zip_4.44/makefile.linux_x86_ppc_alpha__gcc_4.X 2007-04-14 18:51:19.000000000 +0200
+@@ -14,6 +14,6 @@
+ CC=x86_64-pc-linux-gnu-gcc $(ALLFLAGS)
+ LINK_SHARED=-shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+diff -dPNur p7zip_4.44-old/makefile.machine p7zip_4.44/makefile.machine
+--- p7zip_4.44-old/makefile.machine 2007-04-14 15:37:39.000000000 +0200
++++ p7zip_4.44/makefile.machine 2007-04-14 18:49:24.000000000 +0200
+@@ -11,6 +11,6 @@
+ CC=x86_64-pc-linux-gnu-gcc $(ALLFLAGS)
+ LINK_SHARED=-shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
diff --git a/patches/p7zip/p7zip_4.57-ds-rusxmms-full.patch b/patches/p7zip/p7zip_4.57-ds-rusxmms-full.patch
new file mode 100644
index 0000000..24fa504
--- /dev/null
+++ b/patches/p7zip/p7zip_4.57-ds-rusxmms-full.patch
@@ -0,0 +1,419 @@
+diff -dPNur p7zip_4.57/C/rccrecode.c p7zip_4.57-new/C/rccrecode.c
+--- p7zip_4.57/C/rccrecode.c 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.57-new/C/rccrecode.c 2008-04-11 22:02:20.000000000 +0200
+@@ -0,0 +1,71 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "zip");
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++ if (ctx) rccLoad(ctx, "zip");
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip_4.57/C/rccrecode.h p7zip_4.57-new/C/rccrecode.h
+--- p7zip_4.57/C/rccrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.57-new/C/rccrecode.h 2008-04-11 22:02:20.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.cpp 2007-12-08 11:19:00.000000000 +0100
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.cpp 2008-04-11 22:02:20.000000000 +0200
+@@ -9,11 +9,22 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
++
++CInArchive::CInArchive() {
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive() {
++ rcc_free(rccctx);
++}
++
+
+ // static const char kEndOfString = '\0';
+-
++
+ bool CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
+ {
+ m_Stream = inStream;
+@@ -196,10 +207,18 @@
+
+ AString CInArchive::ReadFileName(UInt32 nameSize)
+ {
++ char *rccrec;
+ if (nameSize == 0)
+ return AString();
+ SafeReadBytes(m_NameBuffer.GetBuffer(nameSize), nameSize);
+ m_NameBuffer.ReleaseBuffer(nameSize);
++
++ rccrec = rcc_read(rccctx, (LPCSTR)m_NameBuffer, 0);
++ if (rccrec) {
++ m_NameBuffer = rccrec;
++ free(rccrec);
++ }
++
+ return m_NameBuffer;
+ }
+
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.h p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.h 2007-12-08 11:19:00.000000000 +0100
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.h 2008-04-11 22:02:20.000000000 +0200
+@@ -106,6 +106,10 @@
+ bool SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
++
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
+ };
+
+ }}
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.cpp 2007-06-26 20:06:23.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.cpp 2008-04-11 22:02:20.000000000 +0200
+@@ -7,9 +7,19 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ if (!m_OutBuffer.Create(1 << 16))
+@@ -112,6 +122,7 @@
+ {
+ SeekTo(m_BasePosition);
+
++ char *rccrec;
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+@@ -130,6 +141,12 @@
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("%u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+@@ -154,6 +171,7 @@
+
+ void COutArchive::WriteCentralHeader(const CItem &item)
+ {
++ char *rccrec;
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+@@ -180,6 +198,13 @@
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
++
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("C: %u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.h p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.h 2007-06-26 20:06:22.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.h 2008-04-11 22:02:20.000000000 +0200
+@@ -49,6 +49,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++
+ };
+
+ }}
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Alone/makefile p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile
+--- p7zip_4.57/CPP/7zip/Bundles/Alone/makefile 2007-07-24 20:55:33.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile 2008-04-11 22:02:20.000000000 +0200
+@@ -15,6 +15,7 @@
+ LIBS=$(LOCAL_LIBS)
+
+ OBJS=\
++rccrecode.o \
+ myGetTickCount.o \
+ wine_date_and_time.o \
+ myAddExeFlag.o \
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Alone/makefile.list p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile.list
+--- p7zip_4.57/CPP/7zip/Bundles/Alone/makefile.list 2007-07-24 20:56:10.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile.list 2008-04-11 22:02:20.000000000 +0200
+@@ -196,6 +196,7 @@
+ ../../../../C/Compress/Branch/BranchPPC.c \
+ ../../../../C/Compress/Branch/BranchSPARC.c \
+ ../../../../C/Compress/Branch/BranchX86.c \
++ ../../../../C/rccrecode.c \
+ ../../../../C/7zCrc.c \
+ ../../../../C/Sort.c \
+ ../../../../C/Threads.c \
+@@ -237,6 +238,8 @@
+ $(CXX) $(CFLAGS) ../../../Common/IntToString.cpp
+ ListFileUtils.o : ../../../Common/ListFileUtils.cpp
+ $(CXX) $(CFLAGS) ../../../Common/ListFileUtils.cpp
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CFLAGS) ../../../../C/rccrecode.c
+ MyWindows.o : ../../../Common/MyWindows.cpp
+ $(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp
+ Random.o : ../../../Common/Random.cpp
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile
+--- p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile 2007-08-03 20:16:04.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile 2008-04-11 22:02:20.000000000 +0200
+@@ -14,6 +14,7 @@
+ LIBS=$(LOCAL_LIBS_DLL)
+
+ OBJS = \
++rccrecode.o \
+ wine_date_and_time.o \
+ myGetTickCount.o \
+ CRC.o \
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile.list p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile.list
+--- p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile.list 2007-08-03 20:17:57.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile.list 2008-04-11 22:02:20.000000000 +0200
+@@ -218,6 +218,7 @@
+ ../../../../C/Compress/Branch/BranchPPC.c \
+ ../../../../C/Compress/Branch/BranchSPARC.c \
+ ../../../../C/Compress/Branch/BranchX86.c \
++ ../../../../C/rccrecode.c \
+ ../../../../C/7zCrc.c \
+ ../../../../C/Sort.c \
+ ../../../../C/Threads.c \
+@@ -237,6 +238,8 @@
+ $(CXX) $(CC_SHARED) $(CFLAGS) ../../../Common/ListFileUtils.cpp
+ MyWindows.o : ../../../Common/MyWindows.cpp
+ $(CXX) $(CC_SHARED) $(CFLAGS) ../../../Common/MyWindows.cpp
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CC_SHARED) $(CFLAGS) ../../../../C/rccrecode.c
+ Random.o : ../../../Common/Random.cpp
+ $(CXX) $(CC_SHARED) $(CFLAGS) ../../../Common/Random.cpp
+ StdInStream.o : ../../../Common/StdInStream.cpp
+diff -dPNur p7zip_4.57/makefile.linux_amd64 p7zip_4.57-new/makefile.linux_amd64
+--- p7zip_4.57/makefile.linux_amd64 2007-06-28 09:32:20.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_amd64 2008-04-11 22:02:45.000000000 +0200
+@@ -12,7 +12,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.57/makefile.linux_amd64_asm p7zip_4.57-new/makefile.linux_amd64_asm
+--- p7zip_4.57/makefile.linux_amd64_asm 2007-06-28 09:32:30.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_amd64_asm 2008-04-11 22:02:45.000000000 +0200
+@@ -13,7 +13,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=yasm -f elf -m amd64
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x64
+diff -dPNur p7zip_4.57/makefile.linux_gcc_2.95_no_need_for_libstdc p7zip_4.57-new/makefile.linux_gcc_2.95_no_need_for_libstdc
+--- p7zip_4.57/makefile.linux_gcc_2.95_no_need_for_libstdc 2007-06-24 20:49:31.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_gcc_2.95_no_need_for_libstdc 2008-04-11 22:02:45.000000000 +0200
+@@ -11,7 +11,7 @@
+ LINK_SHARED=-shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.57/makefile.linux_s390x p7zip_4.57-new/makefile.linux_s390x
+--- p7zip_4.57/makefile.linux_s390x 2007-08-07 18:36:01.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_s390x 2008-04-11 22:02:45.000000000 +0200
+@@ -15,7 +15,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.57/makefile.linux_x86_asm_gcc_4.X p7zip_4.57-new/makefile.linux_x86_asm_gcc_4.X
+--- p7zip_4.57/makefile.linux_x86_asm_gcc_4.X 2007-08-08 11:15:07.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_x86_asm_gcc_4.X 2008-04-11 22:02:45.000000000 +0200
+@@ -15,7 +15,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.57/makefile.linux_x86_asm_gcc_4.X_fltk p7zip_4.57-new/makefile.linux_x86_asm_gcc_4.X_fltk
+--- p7zip_4.57/makefile.linux_x86_asm_gcc_4.X_fltk 2007-08-08 11:15:10.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_x86_asm_gcc_4.X_fltk 2008-04-11 22:02:45.000000000 +0200
+@@ -15,7 +15,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread `fltk-config --ldflags`
++LOCAL_LIBS=-lpthread -lrcc `fltk-config --ldflags`
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.57/makefile.linux_x86_asm_icc p7zip_4.57-new/makefile.linux_x86_asm_icc
+--- p7zip_4.57/makefile.linux_x86_asm_icc 2007-08-08 11:15:15.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_x86_asm_icc 2008-04-11 22:02:45.000000000 +0200
+@@ -16,7 +16,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.57/makefile.linux_x86_ppc_alpha p7zip_4.57-new/makefile.linux_x86_ppc_alpha
+--- p7zip_4.57/makefile.linux_x86_ppc_alpha 2007-08-08 11:15:18.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_x86_ppc_alpha 2008-04-11 22:02:45.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.57/makefile.linux_x86_ppc_alpha_gcc_4.X p7zip_4.57-new/makefile.linux_x86_ppc_alpha_gcc_4.X
+--- p7zip_4.57/makefile.linux_x86_ppc_alpha_gcc_4.X 2007-08-08 11:15:20.000000000 +0200
++++ p7zip_4.57-new/makefile.linux_x86_ppc_alpha_gcc_4.X 2008-04-11 22:02:45.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.57/makefile.machine p7zip_4.57-new/makefile.machine
+--- p7zip_4.57/makefile.machine 2007-12-15 18:19:48.000000000 +0100
++++ p7zip_4.57-new/makefile.machine 2008-04-11 22:02:20.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
diff --git a/patches/p7zip/p7zip_4.57-ds-rusxmms.patch b/patches/p7zip/p7zip_4.57-ds-rusxmms.patch
new file mode 100644
index 0000000..0913c13
--- /dev/null
+++ b/patches/p7zip/p7zip_4.57-ds-rusxmms.patch
@@ -0,0 +1,336 @@
+diff -dPNur p7zip_4.57/C/rccrecode.c p7zip_4.57-new/C/rccrecode.c
+--- p7zip_4.57/C/rccrecode.c 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.57-new/C/rccrecode.c 2008-04-11 20:23:42.000000000 +0200
+@@ -0,0 +1,71 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "zip");
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++ if (ctx) rccLoad(ctx, "zip");
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip_4.57/C/rccrecode.h p7zip_4.57-new/C/rccrecode.h
+--- p7zip_4.57/C/rccrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.57-new/C/rccrecode.h 2008-04-11 20:23:42.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.cpp 2007-12-08 11:19:00.000000000 +0100
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.cpp 2008-04-11 20:23:42.000000000 +0200
+@@ -9,11 +9,22 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
++
++CInArchive::CInArchive() {
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive() {
++ rcc_free(rccctx);
++}
++
+
+ // static const char kEndOfString = '\0';
+-
++
+ bool CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
+ {
+ m_Stream = inStream;
+@@ -196,10 +207,18 @@
+
+ AString CInArchive::ReadFileName(UInt32 nameSize)
+ {
++ char *rccrec;
+ if (nameSize == 0)
+ return AString();
+ SafeReadBytes(m_NameBuffer.GetBuffer(nameSize), nameSize);
+ m_NameBuffer.ReleaseBuffer(nameSize);
++
++ rccrec = rcc_read(rccctx, (LPCSTR)m_NameBuffer, 0);
++ if (rccrec) {
++ m_NameBuffer = rccrec;
++ free(rccrec);
++ }
++
+ return m_NameBuffer;
+ }
+
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.h p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipIn.h 2007-12-08 11:19:00.000000000 +0100
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipIn.h 2008-04-11 20:23:42.000000000 +0200
+@@ -106,6 +106,10 @@
+ bool SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
++
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
+ };
+
+ }}
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.cpp 2007-06-26 20:06:23.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.cpp 2008-04-11 20:23:42.000000000 +0200
+@@ -7,9 +7,19 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ if (!m_OutBuffer.Create(1 << 16))
+@@ -112,6 +122,7 @@
+ {
+ SeekTo(m_BasePosition);
+
++ char *rccrec;
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+@@ -130,6 +141,12 @@
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("%u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+@@ -154,6 +171,7 @@
+
+ void COutArchive::WriteCentralHeader(const CItem &item)
+ {
++ char *rccrec;
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+@@ -180,6 +198,13 @@
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
++
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("C: %u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+diff -dPNur p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.h p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip_4.57/CPP/7zip/Archive/Zip/ZipOut.h 2007-06-26 20:06:22.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Archive/Zip/ZipOut.h 2008-04-11 20:23:42.000000000 +0200
+@@ -49,6 +49,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++
+ };
+
+ }}
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Alone/makefile p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile
+--- p7zip_4.57/CPP/7zip/Bundles/Alone/makefile 2007-07-24 20:55:33.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile 2008-04-11 20:23:42.000000000 +0200
+@@ -15,6 +15,7 @@
+ LIBS=$(LOCAL_LIBS)
+
+ OBJS=\
++rccrecode.o \
+ myGetTickCount.o \
+ wine_date_and_time.o \
+ myAddExeFlag.o \
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Alone/makefile.list p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile.list
+--- p7zip_4.57/CPP/7zip/Bundles/Alone/makefile.list 2007-07-24 20:56:10.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Alone/makefile.list 2008-04-11 20:23:42.000000000 +0200
+@@ -196,6 +196,7 @@
+ ../../../../C/Compress/Branch/BranchPPC.c \
+ ../../../../C/Compress/Branch/BranchSPARC.c \
+ ../../../../C/Compress/Branch/BranchX86.c \
++ ../../../../C/rccrecode.c \
+ ../../../../C/7zCrc.c \
+ ../../../../C/Sort.c \
+ ../../../../C/Threads.c \
+@@ -237,6 +238,8 @@
+ $(CXX) $(CFLAGS) ../../../Common/IntToString.cpp
+ ListFileUtils.o : ../../../Common/ListFileUtils.cpp
+ $(CXX) $(CFLAGS) ../../../Common/ListFileUtils.cpp
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CFLAGS) ../../../../C/rccrecode.c
+ MyWindows.o : ../../../Common/MyWindows.cpp
+ $(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp
+ Random.o : ../../../Common/Random.cpp
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile
+--- p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile 2007-08-03 20:16:04.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile 2008-04-11 20:30:53.000000000 +0200
+@@ -14,6 +14,7 @@
+ LIBS=$(LOCAL_LIBS_DLL)
+
+ OBJS = \
++rccrecode.o \
+ wine_date_and_time.o \
+ myGetTickCount.o \
+ CRC.o \
+diff -dPNur p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile.list p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile.list
+--- p7zip_4.57/CPP/7zip/Bundles/Format7zFree/makefile.list 2007-08-03 20:17:57.000000000 +0200
++++ p7zip_4.57-new/CPP/7zip/Bundles/Format7zFree/makefile.list 2008-04-11 20:32:11.000000000 +0200
+@@ -218,6 +218,7 @@
+ ../../../../C/Compress/Branch/BranchPPC.c \
+ ../../../../C/Compress/Branch/BranchSPARC.c \
+ ../../../../C/Compress/Branch/BranchX86.c \
++ ../../../../C/rccrecode.c \
+ ../../../../C/7zCrc.c \
+ ../../../../C/Sort.c \
+ ../../../../C/Threads.c \
+@@ -237,6 +238,8 @@
+ $(CXX) $(CC_SHARED) $(CFLAGS) ../../../Common/ListFileUtils.cpp
+ MyWindows.o : ../../../Common/MyWindows.cpp
+ $(CXX) $(CC_SHARED) $(CFLAGS) ../../../Common/MyWindows.cpp
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CC_SHARED) $(CFLAGS) ../../../../C/rccrecode.c
+ Random.o : ../../../Common/Random.cpp
+ $(CXX) $(CC_SHARED) $(CFLAGS) ../../../Common/Random.cpp
+ StdInStream.o : ../../../Common/StdInStream.cpp
+diff -dPNur p7zip_4.57/makefile.machine p7zip_4.57-new/makefile.machine
+--- p7zip_4.57/makefile.machine 2007-12-15 18:19:48.000000000 +0100
++++ p7zip_4.57-new/makefile.machine 2008-04-11 20:23:42.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.57/makefile.machine.orig p7zip_4.57-new/makefile.machine.orig
+--- p7zip_4.57/makefile.machine.orig 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.57-new/makefile.machine.orig 2007-12-15 18:19:48.000000000 +0100
+@@ -0,0 +1,21 @@
++#
++# makefile for Linux (x86, PPC, alpha ...)
++#
++
++OPTFLAGS=-O
++
++ALLFLAGS=${OPTFLAGS} -s \
++ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
++ -DNDEBUG -D_REENTRANT -DENV_UNIX \
++ $(LOCAL_FLAGS)
++
++CXX=g++ $(ALLFLAGS)
++CC=gcc $(ALLFLAGS)
++CC_SHARED=-fPIC
++LINK_SHARED=-fPIC -shared
++
++LOCAL_LIBS=-lpthread
++LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
++
++OBJ_CRC32=$(OBJ_CRC32_C)
++
diff --git a/patches/p7zip/p7zip_4.65-ds-rusxmms-full.patch b/patches/p7zip/p7zip_4.65-ds-rusxmms-full.patch
new file mode 100644
index 0000000..a7ab04e
--- /dev/null
+++ b/patches/p7zip/p7zip_4.65-ds-rusxmms-full.patch
@@ -0,0 +1,425 @@
+diff -dPNur p7zip_4.65/C/rccrecode.c p7zip_4.65-new/C/rccrecode.c
+--- p7zip_4.65/C/rccrecode.c 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.65-new/C/rccrecode.c 2009-06-14 02:44:19.000000000 +0200
+@@ -0,0 +1,71 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "zip");
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++ if (ctx) rccLoad(ctx, "zip");
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip_4.65/C/rccrecode.h p7zip_4.65-new/C/rccrecode.h
+--- p7zip_4.65/C/rccrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.65-new/C/rccrecode.h 2009-06-14 02:44:19.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.cpp 2008-11-28 23:03:44.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.cpp 2009-06-14 02:47:28.000000000 +0200
+@@ -9,6 +9,8 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ extern "C"
+ {
+ #include "../../../../C/CpuArch.h"
+@@ -23,6 +25,14 @@
+
+ // static const char kEndOfString = '\0';
+
++CInArchive::CInArchive() {
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive() {
++ rcc_free(rccctx);
++}
++
+ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+ {
+ Close();
+@@ -198,12 +208,21 @@
+
+ AString CInArchive::ReadFileName(UInt32 nameSize)
+ {
++ char *rccrec;
++
+ if (nameSize == 0)
+ return AString();
+ char *p = m_NameBuffer.GetBuffer(nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ m_NameBuffer.ReleaseBuffer();
++
++ rccrec = rcc_read(rccctx, (LPCSTR)m_NameBuffer, 0);
++ if (rccrec) {
++ m_NameBuffer = rccrec;
++ free(rccrec);
++ }
++
+ return m_NameBuffer;
+ }
+
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.h p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.h 2008-08-14 11:11:13.000000000 +0200
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.h 2009-06-14 02:48:32.000000000 +0200
+@@ -108,6 +108,10 @@
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
++
+ bool IsOpen() const { return m_Stream != NULL; }
+ };
+
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.cpp 2008-08-14 11:11:26.000000000 +0200
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.cpp 2009-06-14 02:44:19.000000000 +0200
+@@ -7,9 +7,19 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ if (!m_OutBuffer.Create(1 << 16))
+@@ -112,6 +122,7 @@
+ {
+ SeekTo(m_BasePosition);
+
++ char *rccrec;
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+@@ -130,6 +141,12 @@
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("%u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+@@ -154,6 +171,7 @@
+
+ void COutArchive::WriteCentralHeader(const CItem &item)
+ {
++ char *rccrec;
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+@@ -181,6 +199,13 @@
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
++
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("C: %u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.h p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.h 2008-08-14 11:11:13.000000000 +0200
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.h 2009-06-14 02:44:19.000000000 +0200
+@@ -49,6 +49,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++
+ };
+
+ }}
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Alone/makefile p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile
+--- p7zip_4.65/CPP/7zip/Bundles/Alone/makefile 2009-02-07 19:39:04.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile 2009-06-14 02:44:19.000000000 +0200
+@@ -250,6 +250,7 @@
+ Sha256.o
+
+ OBJS=\
++rccrecode.o \
+ myGetTickCount.o \
+ wine_date_and_time.o \
+ myAddExeFlag.o \
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Alone/makefile.list p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile.list
+--- p7zip_4.65/CPP/7zip/Bundles/Alone/makefile.list 2009-02-09 21:04:57.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile.list 2009-06-14 02:51:45.000000000 +0200
+@@ -204,6 +204,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/Bra.c \
+ ../../../../C/Bra86.c \
+ ../../../../C/BraIA64.c \
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile
+--- p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile 2009-02-09 21:47:24.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile 2009-06-14 03:00:06.000000000 +0200
+@@ -296,6 +296,7 @@
+ Sha256.o \
+
+ OBJS = \
++ rccrecode.o \
+ wine_date_and_time.o \
+ myGetTickCount.o \
+ $(COMMON_OBJS) \
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile.list p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile.list
+--- p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-02-09 21:04:32.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-06-14 03:00:39.000000000 +0200
+@@ -235,6 +235,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/Bra.c \
+ ../../../../C/Bra86.c \
+ ../../../../C/BraIA64.c \
+diff -dPNur p7zip_4.65/makefile.linux_amd64 p7zip_4.65-new/makefile.linux_amd64
+--- p7zip_4.65/makefile.linux_amd64 2007-06-28 09:32:20.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_amd64 2009-06-14 05:08:19.000000000 +0200
+@@ -12,7 +12,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.65/makefile.linux_amd64_asm p7zip_4.65-new/makefile.linux_amd64_asm
+--- p7zip_4.65/makefile.linux_amd64_asm 2007-06-28 09:32:30.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_amd64_asm 2009-06-14 05:08:19.000000000 +0200
+@@ -13,7 +13,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=yasm -f elf -m amd64
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x64
+diff -dPNur p7zip_4.65/makefile.linux_amd64_asm_icc p7zip_4.65-new/makefile.linux_amd64_asm_icc
+--- p7zip_4.65/makefile.linux_amd64_asm_icc 2009-02-09 22:12:36.000000000 +0100
++++ p7zip_4.65-new/makefile.linux_amd64_asm_icc 2009-06-14 05:08:19.000000000 +0200
+@@ -16,7 +16,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=yasm -f elf -m amd64
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x64
+diff -dPNur p7zip_4.65/makefile.linux_gcc_2.95_no_need_for_libstdc p7zip_4.65-new/makefile.linux_gcc_2.95_no_need_for_libstdc
+--- p7zip_4.65/makefile.linux_gcc_2.95_no_need_for_libstdc 2007-06-24 20:49:31.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_gcc_2.95_no_need_for_libstdc 2009-06-14 05:08:19.000000000 +0200
+@@ -11,7 +11,7 @@
+ LINK_SHARED=-shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.65/makefile.linux_s390x p7zip_4.65-new/makefile.linux_s390x
+--- p7zip_4.65/makefile.linux_s390x 2007-08-07 18:36:01.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_s390x 2009-06-14 05:08:19.000000000 +0200
+@@ -15,7 +15,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.65/makefile.linux_x86_asm_gcc_4.X p7zip_4.65-new/makefile.linux_x86_asm_gcc_4.X
+--- p7zip_4.65/makefile.linux_x86_asm_gcc_4.X 2007-08-08 11:15:07.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_x86_asm_gcc_4.X 2009-06-14 05:08:19.000000000 +0200
+@@ -15,7 +15,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.65/makefile.linux_x86_asm_gcc_4.X_fltk p7zip_4.65-new/makefile.linux_x86_asm_gcc_4.X_fltk
+--- p7zip_4.65/makefile.linux_x86_asm_gcc_4.X_fltk 2007-08-08 11:15:10.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_x86_asm_gcc_4.X_fltk 2009-06-14 05:08:19.000000000 +0200
+@@ -15,7 +15,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread `fltk-config --ldflags`
++LOCAL_LIBS=-lpthread -lrcc `fltk-config --ldflags`
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.65/makefile.linux_x86_asm_icc p7zip_4.65-new/makefile.linux_x86_asm_icc
+--- p7zip_4.65/makefile.linux_x86_asm_icc 2007-08-08 11:15:15.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_x86_asm_icc 2009-06-14 05:08:19.000000000 +0200
+@@ -16,7 +16,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip_4.65/makefile.linux_x86_ppc_alpha p7zip_4.65-new/makefile.linux_x86_ppc_alpha
+--- p7zip_4.65/makefile.linux_x86_ppc_alpha 2007-08-08 11:15:18.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_x86_ppc_alpha 2009-06-14 05:08:19.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.65/makefile.linux_x86_ppc_alpha_gcc_4.X p7zip_4.65-new/makefile.linux_x86_ppc_alpha_gcc_4.X
+--- p7zip_4.65/makefile.linux_x86_ppc_alpha_gcc_4.X 2007-08-08 11:15:20.000000000 +0200
++++ p7zip_4.65-new/makefile.linux_x86_ppc_alpha_gcc_4.X 2009-06-14 05:08:19.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.65/makefile.machine p7zip_4.65-new/makefile.machine
+--- p7zip_4.65/makefile.machine 2009-02-14 18:19:09.000000000 +0100
++++ p7zip_4.65-new/makefile.machine 2009-06-14 02:44:19.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.65/makefile.rules p7zip_4.65-new/makefile.rules
+--- p7zip_4.65/makefile.rules 2009-02-09 21:03:16.000000000 +0100
++++ p7zip_4.65-new/makefile.rules 2009-06-14 02:52:48.000000000 +0200
+@@ -558,3 +558,5 @@
+ 7zCrcT8.o : ../../../../C/7zCrcT8.c
+ $(CC) $(CFLAGS) ../../../../C/7zCrcT8.c
+
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CFLAGS) ../../../../C/rccrecode.c
diff --git a/patches/p7zip/p7zip_4.65-ds-rusxmms.patch b/patches/p7zip/p7zip_4.65-ds-rusxmms.patch
new file mode 100644
index 0000000..7072522
--- /dev/null
+++ b/patches/p7zip/p7zip_4.65-ds-rusxmms.patch
@@ -0,0 +1,305 @@
+diff -dPNur p7zip_4.65/C/rccrecode.c p7zip_4.65-new/C/rccrecode.c
+--- p7zip_4.65/C/rccrecode.c 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.65-new/C/rccrecode.c 2009-06-14 02:44:19.000000000 +0200
+@@ -0,0 +1,71 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "zip");
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++ if (ctx) rccLoad(ctx, "zip");
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip_4.65/C/rccrecode.h p7zip_4.65-new/C/rccrecode.h
+--- p7zip_4.65/C/rccrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ p7zip_4.65-new/C/rccrecode.h 2009-06-14 02:44:19.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.cpp 2008-11-28 23:03:44.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.cpp 2009-06-14 02:47:28.000000000 +0200
+@@ -9,6 +9,8 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ extern "C"
+ {
+ #include "../../../../C/CpuArch.h"
+@@ -23,6 +25,14 @@
+
+ // static const char kEndOfString = '\0';
+
++CInArchive::CInArchive() {
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive() {
++ rcc_free(rccctx);
++}
++
+ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+ {
+ Close();
+@@ -198,12 +208,21 @@
+
+ AString CInArchive::ReadFileName(UInt32 nameSize)
+ {
++ char *rccrec;
++
+ if (nameSize == 0)
+ return AString();
+ char *p = m_NameBuffer.GetBuffer(nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ m_NameBuffer.ReleaseBuffer();
++
++ rccrec = rcc_read(rccctx, (LPCSTR)m_NameBuffer, 0);
++ if (rccrec) {
++ m_NameBuffer = rccrec;
++ free(rccrec);
++ }
++
+ return m_NameBuffer;
+ }
+
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.h p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipIn.h 2008-08-14 11:11:13.000000000 +0200
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipIn.h 2009-06-14 02:48:32.000000000 +0200
+@@ -108,6 +108,10 @@
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
++
+ bool IsOpen() const { return m_Stream != NULL; }
+ };
+
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.cpp 2008-08-14 11:11:26.000000000 +0200
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.cpp 2009-06-14 02:44:19.000000000 +0200
+@@ -7,9 +7,19 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ if (!m_OutBuffer.Create(1 << 16))
+@@ -112,6 +122,7 @@
+ {
+ SeekTo(m_BasePosition);
+
++ char *rccrec;
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+@@ -130,6 +141,12 @@
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("%u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+@@ -154,6 +171,7 @@
+
+ void COutArchive::WriteCentralHeader(const CItem &item)
+ {
++ char *rccrec;
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+@@ -181,6 +199,13 @@
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
++
++ rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) {
++ printf("C: %u, %s.\n", item.Name.Length(), rccrec);
++ WriteBytes(rccrec, strlen(rccrec));
++ free(rccrec);
++ } else
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+diff -dPNur p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.h p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip_4.65/CPP/7zip/Archive/Zip/ZipOut.h 2008-08-14 11:11:13.000000000 +0200
++++ p7zip_4.65-new/CPP/7zip/Archive/Zip/ZipOut.h 2009-06-14 02:44:19.000000000 +0200
+@@ -49,6 +49,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++
+ };
+
+ }}
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Alone/makefile p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile
+--- p7zip_4.65/CPP/7zip/Bundles/Alone/makefile 2009-02-07 19:39:04.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile 2009-06-14 02:44:19.000000000 +0200
+@@ -250,6 +250,7 @@
+ Sha256.o
+
+ OBJS=\
++rccrecode.o \
+ myGetTickCount.o \
+ wine_date_and_time.o \
+ myAddExeFlag.o \
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Alone/makefile.list p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile.list
+--- p7zip_4.65/CPP/7zip/Bundles/Alone/makefile.list 2009-02-09 21:04:57.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Alone/makefile.list 2009-06-14 02:51:45.000000000 +0200
+@@ -204,6 +204,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/Bra.c \
+ ../../../../C/Bra86.c \
+ ../../../../C/BraIA64.c \
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile
+--- p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile 2009-02-09 21:47:24.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile 2009-06-14 03:00:06.000000000 +0200
+@@ -296,6 +296,7 @@
+ Sha256.o \
+
+ OBJS = \
++ rccrecode.o \
+ wine_date_and_time.o \
+ myGetTickCount.o \
+ $(COMMON_OBJS) \
+diff -dPNur p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile.list p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile.list
+--- p7zip_4.65/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-02-09 21:04:32.000000000 +0100
++++ p7zip_4.65-new/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-06-14 03:00:39.000000000 +0200
+@@ -235,6 +235,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/Bra.c \
+ ../../../../C/Bra86.c \
+ ../../../../C/BraIA64.c \
+diff -dPNur p7zip_4.65/makefile.machine p7zip_4.65-new/makefile.machine
+--- p7zip_4.65/makefile.machine 2009-02-14 18:19:09.000000000 +0100
++++ p7zip_4.65-new/makefile.machine 2009-06-14 02:44:19.000000000 +0200
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip_4.65/makefile.rules p7zip_4.65-new/makefile.rules
+--- p7zip_4.65/makefile.rules 2009-02-09 21:03:16.000000000 +0100
++++ p7zip_4.65-new/makefile.rules 2009-06-14 02:52:48.000000000 +0200
+@@ -558,3 +558,5 @@
+ 7zCrcT8.o : ../../../../C/7zCrcT8.c
+ $(CC) $(CFLAGS) ../../../../C/7zCrcT8.c
+
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CFLAGS) ../../../../C/rccrecode.c
diff --git a/patches/p7zip/p7zip_9.04-ds-rusxmms-full.patch b/patches/p7zip/p7zip_9.04-ds-rusxmms-full.patch
new file mode 100644
index 0000000..d44a16f
--- /dev/null
+++ b/patches/p7zip/p7zip_9.04-ds-rusxmms-full.patch
@@ -0,0 +1,414 @@
+diff -dPNur p7zip-9.04~dfsg.1/C/rccrecode.c p7zip-9.04~dfsg.1-ds/C/rccrecode.c
+--- p7zip-9.04~dfsg.1/C/rccrecode.c 1970-01-01 03:00:00.000000000 +0300
++++ p7zip-9.04~dfsg.1-ds/C/rccrecode.c 2009-10-28 03:29:23.000000000 +0300
+@@ -0,0 +1,71 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "zip");
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++ if (ctx) rccLoad(ctx, "zip");
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip-9.04~dfsg.1/C/rccrecode.h p7zip-9.04~dfsg.1-ds/C/rccrecode.h
+--- p7zip-9.04~dfsg.1/C/rccrecode.h 1970-01-01 03:00:00.000000000 +0300
++++ p7zip-9.04~dfsg.1-ds/C/rccrecode.h 2009-10-28 03:29:23.000000000 +0300
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.cpp 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.cpp 2009-10-28 03:49:06.000000000 +0300
+@@ -9,6 +9,8 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ #include "ZipIn.h"
+
+ #define Get16(p) GetUi16(p)
+@@ -17,7 +19,17 @@
+
+ namespace NArchive {
+ namespace NZip {
+-
++
++CInArchive::CInArchive()
++{
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive()
++{
++ rcc_free(rccctx);
++}
++
+ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+ {
+ _inBufMode = false;
+@@ -200,12 +212,20 @@
+
+ void CInArchive::ReadFileName(UInt32 nameSize, AString &dest)
+ {
++ char *rccrec;
++
+ if (nameSize == 0)
+ dest.Empty();
+ char *p = dest.GetBuffer((int)nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ dest.ReleaseBuffer();
++
++ rccrec = rcc_read(rccctx, (LPCSTR)dest, 0);
++ if (rccrec) {
++ dest = rccrec;
++ free(rccrec);
++ }
+ }
+
+ void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.h p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.h 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.h 2009-10-28 03:29:23.000000000 +0300
+@@ -114,6 +114,10 @@
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
++
+ bool IsOpen() const { return m_Stream != NULL; }
+ };
+
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.h p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.h 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.h 2009-10-28 05:49:05.000000000 +0300
+@@ -49,6 +49,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++ void Recode(CItem &item);
+ };
+
+ }}
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipUpdate.cpp p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2009-10-28 05:48:04.000000000 +0300
+@@ -87,6 +87,7 @@
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
++ archive.Recode(item);
+ }
+ else
+ isDir = item.IsDir();
+@@ -359,9 +360,11 @@
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+
++ archive.Recode(item);
++
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
+-
++
+ archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ archive.SeekToPackedDataPosition();
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile 2009-10-28 03:29:24.000000000 +0300
+@@ -244,6 +244,7 @@
+
+
+ OBJS=\
++rccrecode.o \
+ myGetTickCount.o \
+ wine_date_and_time.o \
+ myAddExeFlag.o \
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile.list p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile.list
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile.list 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile.list 2009-10-28 03:40:17.000000000 +0300
+@@ -192,6 +192,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/Aes.c \
+ ../../../../C/7zStream.c \
+ ../../../../C/Bra.c \
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile 2009-10-28 03:29:24.000000000 +0300
+@@ -284,6 +284,7 @@
+
+
+ OBJS = \
++ rccrecode.o \
+ wine_date_and_time.o \
+ myGetTickCount.o \
+ $(COMMON_OBJS) \
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile.list p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile.list
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-10-28 03:34:02.000000000 +0300
+@@ -218,6 +218,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/7zBuf2.c \
+ ../../../../C/7zStream.c \
+ ../../../../C/Aes.c \
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_amd64 p7zip-9.04~dfsg.1-ds/makefile.linux_amd64
+--- p7zip-9.04~dfsg.1/makefile.linux_amd64 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_amd64 2009-10-28 03:54:47.000000000 +0300
+@@ -12,7 +12,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_amd64_asm p7zip-9.04~dfsg.1-ds/makefile.linux_amd64_asm
+--- p7zip-9.04~dfsg.1/makefile.linux_amd64_asm 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_amd64_asm 2009-10-28 03:54:47.000000000 +0300
+@@ -13,7 +13,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=yasm -f elf -m amd64
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x64
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_amd64_asm_icc p7zip-9.04~dfsg.1-ds/makefile.linux_amd64_asm_icc
+--- p7zip-9.04~dfsg.1/makefile.linux_amd64_asm_icc 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_amd64_asm_icc 2009-10-28 03:54:47.000000000 +0300
+@@ -16,7 +16,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=yasm -f elf -m amd64
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x64
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_gcc_2.95_no_need_for_libstdc p7zip-9.04~dfsg.1-ds/makefile.linux_gcc_2.95_no_need_for_libstdc
+--- p7zip-9.04~dfsg.1/makefile.linux_gcc_2.95_no_need_for_libstdc 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_gcc_2.95_no_need_for_libstdc 2009-10-28 03:54:47.000000000 +0300
+@@ -11,7 +11,7 @@
+ LINK_SHARED=-shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_s390x p7zip-9.04~dfsg.1-ds/makefile.linux_s390x
+--- p7zip-9.04~dfsg.1/makefile.linux_s390x 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_s390x 2009-10-28 03:54:47.000000000 +0300
+@@ -15,7 +15,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_x86_asm_gcc_4.X p7zip-9.04~dfsg.1-ds/makefile.linux_x86_asm_gcc_4.X
+--- p7zip-9.04~dfsg.1/makefile.linux_x86_asm_gcc_4.X 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_x86_asm_gcc_4.X 2009-10-28 03:54:47.000000000 +0300
+@@ -15,7 +15,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_x86_asm_gcc_4.X_fltk p7zip-9.04~dfsg.1-ds/makefile.linux_x86_asm_gcc_4.X_fltk
+--- p7zip-9.04~dfsg.1/makefile.linux_x86_asm_gcc_4.X_fltk 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_x86_asm_gcc_4.X_fltk 2009-10-28 03:54:47.000000000 +0300
+@@ -15,7 +15,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread `fltk-config --ldflags`
++LOCAL_LIBS=-lpthread -lrcc `fltk-config --ldflags`
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_x86_asm_icc p7zip-9.04~dfsg.1-ds/makefile.linux_x86_asm_icc
+--- p7zip-9.04~dfsg.1/makefile.linux_x86_asm_icc 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_x86_asm_icc 2009-10-28 03:54:47.000000000 +0300
+@@ -16,7 +16,7 @@
+ LINK_SHARED=-fPIC -shared
+ ASM=nasm -f elf
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ CPU=x86
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_x86_ppc_alpha p7zip-9.04~dfsg.1-ds/makefile.linux_x86_ppc_alpha
+--- p7zip-9.04~dfsg.1/makefile.linux_x86_ppc_alpha 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_x86_ppc_alpha 2009-10-28 03:54:47.000000000 +0300
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip-9.04~dfsg.1/makefile.linux_x86_ppc_alpha_gcc_4.X p7zip-9.04~dfsg.1-ds/makefile.linux_x86_ppc_alpha_gcc_4.X
+--- p7zip-9.04~dfsg.1/makefile.linux_x86_ppc_alpha_gcc_4.X 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.linux_x86_ppc_alpha_gcc_4.X 2009-10-28 03:54:47.000000000 +0300
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip-9.04~dfsg.1/makefile.machine p7zip-9.04~dfsg.1-ds/makefile.machine
+--- p7zip-9.04~dfsg.1/makefile.machine 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.machine 2009-10-28 03:29:24.000000000 +0300
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip-9.04~dfsg.1/makefile.rules p7zip-9.04~dfsg.1-ds/makefile.rules
+--- p7zip-9.04~dfsg.1/makefile.rules 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.rules 2009-10-28 03:29:24.000000000 +0300
+@@ -586,3 +586,5 @@
+ 7zCrcT8.o : ../../../../C/7zCrcT8.c
+ $(CC) $(CFLAGS) ../../../../C/7zCrcT8.c
+
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CFLAGS) ../../../../C/rccrecode.c
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.cpp 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.cpp 2009-10-28 05:49:01.000000000 +0300
+@@ -7,9 +7,24 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
++void COutArchive::Recode(CItem &item) {
++ char *rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) item.Name = rccrec;
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ if (!m_OutBuffer.Create(1 << 16))
diff --git a/patches/p7zip/p7zip_9.04-ds-rusxmms.patch b/patches/p7zip/p7zip_9.04-ds-rusxmms.patch
new file mode 100644
index 0000000..7678241
--- /dev/null
+++ b/patches/p7zip/p7zip_9.04-ds-rusxmms.patch
@@ -0,0 +1,294 @@
+diff -dPNur p7zip-9.04~dfsg.1/C/rccrecode.c p7zip-9.04~dfsg.1-ds/C/rccrecode.c
+--- p7zip-9.04~dfsg.1/C/rccrecode.c 1970-01-01 03:00:00.000000000 +0300
++++ p7zip-9.04~dfsg.1-ds/C/rccrecode.c 2009-10-28 03:29:23.000000000 +0300
+@@ -0,0 +1,71 @@
++#include <pthread.h>
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define ARC_CLASS 0
++#define OUT_CLASS 1
++#define ARCOUT_CLASS 0
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM Encoding", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL, RCC_CLASS_STANDARD, NULL, NULL, NULL, 0 }
++};
++
++static int initialized = 0;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void *rcc_init() {
++ rcc_context ctx;
++
++ pthread_mutex_lock(&mutex);
++ if (!initialized) {
++ rccInit();
++ rccInitDefaultContext(NULL, 0, 0, classes, 0);
++ rccLoad(NULL, "zip");
++ rccInitDb4(NULL, NULL, 0);
++ }
++ initialized++;
++ pthread_mutex_unlock(&mutex);
++
++ ctx = rccCreateContext(NULL, 0, 0, classes, 0);
++ if (ctx) rccInitDb4(ctx, NULL, 0);
++ if (ctx) rccLoad(ctx, "zip");
++
++ return ctx;
++}
++
++
++void rcc_free(void *ctx) {
++ if (ctx) rccFreeContext((rcc_context)ctx);
++
++ pthread_mutex_lock(&mutex);
++ if (initialized == 1) rccFree();
++ initialized--;
++ pthread_mutex_unlock(&mutex);
++}
++
++
++char *rcc_read(void *ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, ARC_CLASS, OUT_CLASS, string, size, NULL);
++}
++
++char *rcc_write(rcc_context ctx, const char *string, size_t size) {
++ if (!initialized) {
++ rcc_init();
++ if (!initialized) return NULL;
++ }
++ return rccSizedRecode((rcc_context)ctx, OUT_CLASS, ARCOUT_CLASS, string, size, NULL);
++}
+diff -dPNur p7zip-9.04~dfsg.1/C/rccrecode.h p7zip-9.04~dfsg.1-ds/C/rccrecode.h
+--- p7zip-9.04~dfsg.1/C/rccrecode.h 1970-01-01 03:00:00.000000000 +0300
++++ p7zip-9.04~dfsg.1-ds/C/rccrecode.h 2009-10-28 03:29:23.000000000 +0300
+@@ -0,0 +1,17 @@
++#ifndef _RCC_RECODE_H
++#define _RCC_RECODE_H
++
++# ifdef __cplusplus
++extern "C" {
++# endif
++
++ void *rcc_init();
++ void rcc_free(void *ctx);
++ char *rcc_read(void *ctx, const char *string, size_t size);
++ char *rcc_write(void *ctx, const char *string, size_t size);
++
++# ifdef __cplusplus
++}
++# endif
++
++#endif /* _RCC_RECODE_H */
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.cpp p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.cpp
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.cpp 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.cpp 2009-10-28 03:49:06.000000000 +0300
+@@ -9,6 +9,8 @@
+ #include "../../Common/LimitedStreams.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ #include "ZipIn.h"
+
+ #define Get16(p) GetUi16(p)
+@@ -17,7 +19,17 @@
+
+ namespace NArchive {
+ namespace NZip {
+-
++
++CInArchive::CInArchive()
++{
++ rccctx = rcc_init();
++}
++
++CInArchive::~CInArchive()
++{
++ rcc_free(rccctx);
++}
++
+ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+ {
+ _inBufMode = false;
+@@ -200,12 +212,20 @@
+
+ void CInArchive::ReadFileName(UInt32 nameSize, AString &dest)
+ {
++ char *rccrec;
++
+ if (nameSize == 0)
+ dest.Empty();
+ char *p = dest.GetBuffer((int)nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ dest.ReleaseBuffer();
++
++ rccrec = rcc_read(rccctx, (LPCSTR)dest, 0);
++ if (rccrec) {
++ dest = rccrec;
++ free(rccrec);
++ }
+ }
+
+ void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.h p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.h
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipIn.h 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipIn.h 2009-10-28 03:29:23.000000000 +0300
+@@ -114,6 +114,10 @@
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
++ void *rccctx;
++ CInArchive();
++ ~CInArchive();
++
+ bool IsOpen() const { return m_Stream != NULL; }
+ };
+
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.h p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.h
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.h 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.h 2009-10-28 05:49:05.000000000 +0300
+@@ -49,6 +49,11 @@
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
++
++ void *rccctx;
++ COutArchive();
++ ~COutArchive();
++ void Recode(CItem &item);
+ };
+
+ }}
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipUpdate.cpp p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2009-10-28 05:48:04.000000000 +0300
+@@ -87,6 +87,7 @@
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
++ archive.Recode(item);
+ }
+ else
+ isDir = item.IsDir();
+@@ -359,9 +360,11 @@
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+
++ archive.Recode(item);
++
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
+-
++
+ archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ archive.SeekToPackedDataPosition();
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile 2009-10-28 03:29:24.000000000 +0300
+@@ -244,6 +244,7 @@
+
+
+ OBJS=\
++rccrecode.o \
+ myGetTickCount.o \
+ wine_date_and_time.o \
+ myAddExeFlag.o \
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile.list p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile.list
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Alone/makefile.list 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Alone/makefile.list 2009-10-28 03:40:17.000000000 +0300
+@@ -192,6 +192,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/Aes.c \
+ ../../../../C/7zStream.c \
+ ../../../../C/Bra.c \
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile 2009-10-28 03:29:24.000000000 +0300
+@@ -284,6 +284,7 @@
+
+
+ OBJS = \
++ rccrecode.o \
+ wine_date_and_time.o \
+ myGetTickCount.o \
+ $(COMMON_OBJS) \
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile.list p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile.list
+--- p7zip-9.04~dfsg.1/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Bundles/Format7zFree/makefile.list 2009-10-28 03:34:02.000000000 +0300
+@@ -218,6 +218,7 @@
+ ../../Crypto/ZipStrong.cpp
+
+ SRCS_C=\
++ ../../../../C/rccrecode.c \
+ ../../../../C/7zBuf2.c \
+ ../../../../C/7zStream.c \
+ ../../../../C/Aes.c \
+diff -dPNur p7zip-9.04~dfsg.1/makefile.machine p7zip-9.04~dfsg.1-ds/makefile.machine
+--- p7zip-9.04~dfsg.1/makefile.machine 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.machine 2009-10-28 03:29:24.000000000 +0300
+@@ -14,7 +14,7 @@
+ CC_SHARED=-fPIC
+ LINK_SHARED=-fPIC -shared
+
+-LOCAL_LIBS=-lpthread
++LOCAL_LIBS=-lpthread -lrcc
+ LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+
+ OBJ_CRC32=$(OBJ_CRC32_C)
+diff -dPNur p7zip-9.04~dfsg.1/makefile.rules p7zip-9.04~dfsg.1-ds/makefile.rules
+--- p7zip-9.04~dfsg.1/makefile.rules 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/makefile.rules 2009-10-28 03:29:24.000000000 +0300
+@@ -586,3 +586,5 @@
+ 7zCrcT8.o : ../../../../C/7zCrcT8.c
+ $(CC) $(CFLAGS) ../../../../C/7zCrcT8.c
+
++rccrecode.o : ../../../../C/rccrecode.c
++ $(CC) $(CFLAGS) ../../../../C/rccrecode.c
+diff -dPNur p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.cpp p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.cpp
+--- p7zip-9.04~dfsg.1/CPP/7zip/Archive/Zip/ZipOut.cpp 2009-06-27 18:18:14.000000000 +0400
++++ p7zip-9.04~dfsg.1-ds/CPP/7zip/Archive/Zip/ZipOut.cpp 2009-10-28 05:49:01.000000000 +0300
+@@ -7,9 +7,24 @@
+ #include "../../Common/OffsetStream.h"
+ #include "../../Common/StreamUtils.h"
+
++#include "../../../../C/rccrecode.h"
++
+ namespace NArchive {
+ namespace NZip {
+
++COutArchive::COutArchive() {
++ rccctx = rcc_init();
++}
++
++COutArchive::~COutArchive() {
++ rcc_free(rccctx);
++}
++
++void COutArchive::Recode(CItem &item) {
++ char *rccrec = rcc_write(rccctx, (const char *)item.Name, item.Name.Length());
++ if (rccrec) item.Name = rccrec;
++}
++
+ void COutArchive::Create(IOutStream *outStream)
+ {
+ if (!m_OutBuffer.Create(1 << 16))
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)
diff --git a/patches/unzip/README b/patches/unzip/README
new file mode 100644
index 0000000..03c08f6
--- /dev/null
+++ b/patches/unzip/README
@@ -0,0 +1,30 @@
+You can use patch in two modes:
+ standard: The unzip will be dynamically linked with librcc (In that case
+ some problems with building OpenOffice from sources may arise)
+
+ lazy: In this case the librcc will be dynamically loaded (with help of
+ dlopen, dlsym) during execution.
+
+
+Usage
+=====
+1. Apply patches: unzip-*-ds-rusxmms.patch, unzip-ds-unixenc.patch
+2. In the root of `unzip` source tree run either `update_shared` for standard
+mode or `update_lazy` for lazy mode.
+
+
+Configuration
+=============
+ - The patch uses "zip" configuration of RCC. This means settings could be
+ altered using "rcc-gtk2-config zip".
+ - ZIP OEM / ZIP ISO / Output - encodings are important for patch.
+
+
+Build
+=====
+ On Unix, call following command to get list of possible targets:
+ make -f unix/Makefile list
+ and then just build with:
+ make -f unix/Makefile <target>
+ for example:
+ make -f unix/Makefile linux_noasm
diff --git a/patches/unzip/unzip-5.52-ds-rusxmms.patch b/patches/unzip/unzip-5.52-ds-rusxmms.patch
new file mode 100644
index 0000000..87835f0
--- /dev/null
+++ b/patches/unzip/unzip-5.52-ds-rusxmms.patch
@@ -0,0 +1,159 @@
+diff -dPNur unzip-5.52/dsrecode.h unzip-5.52-ds/dsrecode.h
+--- unzip-5.52/dsrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ unzip-5.52-ds/dsrecode.h 2008-04-11 22:24:24.000000000 +0200
+@@ -0,0 +1,128 @@
++#include <librcc.h>
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define OEM_CLASS 0
++#define ISO_CLASS 1
++#define OUT_CLASS 2
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM_INTERN", 0 },
++ { "iso", RCC_CLASS_STANDARD, NULL, default_iso, "ISO_INTERN", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL }
++};
++
++int initialized = 0;
++
++#ifdef RCC_LAZY
++#include <dlfcn.h>
++# define RCC_LIBRARY "librcc.so.0"
++int (*rccInit2)();
++int (*rccFree2)();
++int (*rccInitDefaultContext2)(const char *locale_variable, unsigned int max_languages, unsigned int max_classes, rcc_class_ptr defclasses, rcc_init_flags flags);
++int (*rccInitDb42)(rcc_context ctx, const char *name, rcc_db4_flags flags);
++char* (*rccSizedRecode2)(rcc_context ctx, rcc_class_id from, rcc_class_id to, const char *buf, size_t len, size_t *rlen);
++int (*rccLoad2)(rcc_context ctx, const char *name);
++
++
++static char *rccRecode2(rcc_context ctx, rcc_class_id from, rcc_class_id to, const char *buf) {
++ return rccSizedRecode2(ctx, from, to, buf, 0, NULL);
++}
++
++void *rcc_handle;
++#else /* RCC_LAZY */
++#define rccInit2 rccInit
++#define rccFree2 rccFree
++#define rccInitDefaultContext2 rccInitDefaultContext
++#define rccInitDb42 rccInitDb4
++#define rccRecode2 rccRecode
++#define rccLoad2 rccLoad
++#endif /* RCC_LAZY */
++
++static void rccUnzipFree() {
++ if (initialized > 0) {
++ rccFree2();
++#ifdef RCC_LAZY
++ dlclose(rcc_handle);
++#endif /* RCC_LAZY */
++ initialized = 0;
++ }
++}
++
++
++static int rccUnzipInit() {
++ if (initialized) return 0;
++
++#ifdef RCC_LAZY
++ if (sizeof(size_t) == 8) {
++ rcc_handle = dlopen("/usr/lib64/" RCC_LIBRARY, RTLD_NOW);
++ if (!rcc_handle) rcc_handle = dlopen("/usr/local/lib64/" RCC_LIBRARY, RTLD_NOW);
++ } else {
++ rcc_handle = dlopen("/usr/lib32/" RCC_LIBRARY, RTLD_NOW);
++ if (!rcc_handle) rcc_handle = dlopen("/usr/local/lib32/" RCC_LIBRARY, RTLD_NOW);
++ }
++ if (!rcc_handle) {
++ rcc_handle = dlopen("/usr/lib/" RCC_LIBRARY, RTLD_NOW);
++ if (!rcc_handle) rcc_handle = dlopen("/usr/local/lib/" RCC_LIBRARY, RTLD_NOW);
++ }
++ if (!rcc_handle) {
++ initialized = -1;
++ return 1;
++ }
++
++ rccInit2 = dlsym(rcc_handle, "rccInit");
++ rccFree2 = dlsym(rcc_handle, "rccFree");
++ rccInitDefaultContext2 = dlsym(rcc_handle, "rccInitDefaultContext");
++ rccInitDb42 = dlsym(rcc_handle, "rccInitDb4");
++ rccSizedRecode2 = dlsym(rcc_handle, "rccSizedRecode");
++ rccLoad2 = dlsym(rcc_handle, "rccLoad");
++
++ if ((!rccInit2)||(!rccFree2)||(!rccInitDefaultContext2)||(!rccInitDb42)||(!rccSizedRecode2)||(!rccLoad2)) {
++ dlclose(rcc_handle);
++ initialized = -1;
++ return 1;
++ }
++#endif /* RCC_LAZY */
++
++ rccInit2();
++ rccInitDefaultContext2(NULL, 0, 0, classes, 0);
++ rccLoad2(NULL, "zip");
++ rccInitDb42(NULL, NULL, 0);
++ atexit(rccUnzipFree);
++ initialized = 1;
++ return 0;
++}
++
++
++
++void _DS_OEM_INTERN(char *string) {
++ char *str;
++ rccUnzipInit();
++ if (initialized>0) {
++ str = rccRecode2(NULL, OEM_CLASS, OUT_CLASS, string);
++ if (str) {
++ strncpy(string,str,FILNAMSIZ);
++ free(str);
++ }
++ }
++}
++
++void _DS_ISO_INTERN(char *string) {
++ char *str;
++ rccUnzipInit();
++ if (initialized>0) {
++ str = rccRecode2(NULL, ISO_CLASS, OUT_CLASS, string);
++ if (str) {
++ strncpy(string,str,FILNAMSIZ);
++ free(str);
++ }
++ }
++}
+diff -dPNur unzip-5.52/fileio.c unzip-5.52-ds/fileio.c
+--- unzip-5.52/fileio.c 2005-02-27 03:10:12.000000000 +0100
++++ unzip-5.52-ds/fileio.c 2008-04-11 22:25:31.000000000 +0200
+@@ -78,7 +78,7 @@
+ # endif
+ #endif
+ #include "ebcdic.h" /* definition/initialization of ebcdic[] */
+-
++#include "dsrecode.h"
+
+ /*
+ Note: Under Windows, the maximum size of the buffer that can be used
+diff -dPNur unzip-5.52/unzpriv.h unzip-5.52-ds/unzpriv.h
+--- unzip-5.52/unzpriv.h 2005-02-04 00:26:42.000000000 +0100
++++ unzip-5.52-ds/unzpriv.h 2008-04-11 22:25:31.000000000 +0200
+@@ -2564,9 +2564,9 @@
+ ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
+ (hostnum) == FS_HPFS_ || \
+ ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
+- _OEM_INTERN((string)); \
++ _DS_OEM_INTERN((string)); \
+ } else { \
+- _ISO_INTERN((string)); \
++ _DS_ISO_INTERN((string)); \
+ }
+ #endif
+
diff --git a/patches/unzip/unzip-5.52-ds-rusxmms2.patch b/patches/unzip/unzip-5.52-ds-rusxmms2.patch
new file mode 100644
index 0000000..6670a10
--- /dev/null
+++ b/patches/unzip/unzip-5.52-ds-rusxmms2.patch
@@ -0,0 +1,149 @@
+diff -dPNur unzip-5.52/fileio.c unzip-5.52-ds/fileio.c
+--- unzip-5.52/fileio.c 2005-02-27 03:10:12.000000000 +0100
++++ unzip-5.52-ds/fileio.c 2008-04-11 22:25:31.000000000 +0200
+@@ -78,7 +78,7 @@
+ # endif
+ #endif
+ #include "ebcdic.h" /* definition/initialization of ebcdic[] */
+-
++#include "dsrecode.h"
+
+ /*
+ Note: Under Windows, the maximum size of the buffer that can be used
+diff -dPNur unzip-5.52/unzpriv.h unzip-5.52-ds/unzpriv.h
+--- unzip-5.52/unzpriv.h 2005-02-04 00:26:42.000000000 +0100
++++ unzip-5.52-ds/unzpriv.h 2008-04-11 22:25:31.000000000 +0200
+@@ -2564,9 +2564,9 @@
+ ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
+ (hostnum) == FS_HPFS_ || \
+ ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
+- _OEM_INTERN((string)); \
++ _DS_OEM_INTERN((string)); \
+ } else { \
+- _ISO_INTERN((string)); \
++ _DS_ISO_INTERN((string)); \
+ }
+ #endif
+
+diff -dPNur unzip-5.52/dsrecode.h unzip-5.52-ds/dsrecode.h
+--- unzip-5.52/dsrecode.h 1970-01-01 01:00:00.000000000 +0100
++++ unzip-5.52-ds/dsrecode.h 2008-04-11 22:24:24.000000000 +0200
+@@ -0,0 +1,118 @@
++#include "librcc.h"
++
++static rcc_class_default_charset default_oem[] = {
++ { "ru", "IBM866" },
++ { NULL, NULL }
++};
++
++static rcc_class_default_charset default_iso[] = {
++ { "ru", "CP1251" },
++ { NULL, NULL }
++};
++
++#define OEM_CLASS 0
++#define ISO_CLASS 1
++#define OUT_CLASS 2
++static rcc_class classes[] = {
++ { "oem", RCC_CLASS_STANDARD, NULL, default_oem, "OEM_INTERN", 0 },
++ { "iso", RCC_CLASS_STANDARD, NULL, default_iso, "ISO_INTERN", 0 },
++ { "out", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output", 0 },
++ { NULL }
++};
++
++int initialized = 0;
++
++#ifdef RCC_LAZY
++#include <dlfcn.h>
++# define RCC_LIBRARY "librcc.so.0"
++int (*rccInit2)();
++int (*rccFree2)();
++int (*rccInitDefaultContext2)(const char *locale_variable, unsigned int max_languages, unsigned int max_classes, rcc_class_ptr defclasses, rcc_init_flags flags);
++int (*rccInitDb42)(rcc_context ctx, const char *name, rcc_db4_flags flags);
++char* (*rccSizedRecode2)(rcc_context ctx, rcc_class_id from, rcc_class_id to, const char *buf, size_t len, size_t *rlen);
++int (*rccLoad2)(rcc_context ctx, const char *name);
++
++
++static char *rccRecode2(rcc_context ctx, rcc_class_id from, rcc_class_id to, const char *buf) {
++ return rccSizedRecode2(ctx, from, to, buf, 0, NULL);
++}
++
++void *rcc_handle;
++#else /* RCC_LAZY */
++#define rccInit2 rccInit
++#define rccFree2 rccFree
++#define rccInitDefaultContext2 rccInitDefaultContext
++#define rccInitDb42 rccInitDb4
++#define rccRecode2 rccRecode
++#define rccLoad2 rccLoad
++#endif /* RCC_LAZY */
++
++static void rccUnzipFree() {
++ if (initialized > 0) {
++ rccFree2();
++#ifdef RCC_LAZY
++ dlclose(rcc_handle);
++#endif /* RCC_LAZY */
++ initialized = 0;
++ }
++}
++
++
++static int rccUnzipInit() {
++ if (initialized) return 0;
++
++#ifdef RCC_LAZY
++ rcc_handle = dlopen(RCC_LIBRARY, RTLD_NOW);
++ if (!rcc_handle) {
++ initialized = -1;
++ return 1;
++ }
++
++ rccInit2 = dlsym(rcc_handle, "rccInit");
++ rccFree2 = dlsym(rcc_handle, "rccFree");
++ rccInitDefaultContext2 = dlsym(rcc_handle, "rccInitDefaultContext");
++ rccInitDb42 = dlsym(rcc_handle, "rccInitDb4");
++ rccSizedRecode2 = dlsym(rcc_handle, "rccSizedRecode");
++ rccLoad2 = dlsym(rcc_handle, "rccLoad");
++
++ if ((!rccInit2)||(!rccFree2)||(!rccInitDefaultContext2)||(!rccInitDb42)||(!rccSizedRecode2)||(!rccLoad2)) {
++ dlclose(rcc_handle);
++ initialized = -1;
++ return 1;
++ }
++#endif /* RCC_LAZY */
++
++ rccInit2();
++ rccInitDefaultContext2(NULL, 0, 0, classes, 0);
++ rccLoad2(NULL, "zip");
++ rccInitDb42(NULL, NULL, 0);
++ atexit(rccUnzipFree);
++ initialized = 1;
++ return 0;
++}
++
++
++
++void _DS_OEM_INTERN(char *string) {
++ char *str;
++ rccUnzipInit();
++ if (initialized>0) {
++ str = rccRecode2(NULL, OEM_CLASS, OUT_CLASS, string);
++ if (str) {
++ strncpy(string,str,FILNAMSIZ);
++ free(str);
++ }
++ }
++}
++
++void _DS_ISO_INTERN(char *string) {
++ char *str;
++ rccUnzipInit();
++ if (initialized>0) {
++ str = rccRecode2(NULL, ISO_CLASS, OUT_CLASS, string);
++ if (str) {
++ strncpy(string,str,FILNAMSIZ);
++ free(str);
++ }
++ }
++}
diff --git a/patches/unzip/unzip-ds-unixenc.patch b/patches/unzip/unzip-ds-unixenc.patch
new file mode 100644
index 0000000..e33e6ba
--- /dev/null
+++ b/patches/unzip/unzip-ds-unixenc.patch
@@ -0,0 +1,9 @@
+diff -dPNur unzip-5.50/unzpriv.h unzip-5.50-new/unzpriv.h
+--- unzip-5.50/unzpriv.h Sun Feb 17 21:01:48 2002
++++ unzip-5.50-new/unzpriv.h Tue Jun 10 07:16:23 2003
+@@ -2424,4 +2424,5 @@
+ !(((islochdr) || (isuxatt)) && \
+ ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
+ (hostnum) == FS_HPFS_ || \
++ (hostnum) == UNIX_ || \
+ ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
diff --git a/patches/unzip/unzip60-ds-isprint.patch b/patches/unzip/unzip60-ds-isprint.patch
new file mode 100644
index 0000000..64ea1ee
--- /dev/null
+++ b/patches/unzip/unzip60-ds-isprint.patch
@@ -0,0 +1,12 @@
+diff -dPNur unzip60/extract.c unzip60-ds/extract.c
+--- unzip60/extract.c 2009-03-14 02:32:52.000000000 +0100
++++ unzip60-ds/extract.c 2010-07-06 16:34:09.000000000 +0200
+@@ -2596,7 +2596,7 @@
+ */
+ # define UZ_FNFILTER_REPLACECHAR '?'
+ # endif
+- if (!isprint(*r)) {
++ if (*r < 32) { //(!isprint(*r)) {
+ if (*r < 32) {
+ /* ASCII control codes are escaped as "^{letter}". */
+ if (se != NULL && (s > (space + (size-4)))) {
diff --git a/patches/unzip/update_lazy b/patches/unzip/update_lazy
new file mode 100755
index 0000000..de1b04a
--- /dev/null
+++ b/patches/unzip/update_lazy
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+ sed -i \
+ -e "s:-O3:\${CFLAGS}:" \
+ -e "s:CC=gcc :CC=\"gcc -DRCC_LAZY=1\":" \
+ -e "s:LD=gcc :LD=\"gcc \${LDFLAGS} -ldl\" :" \
+ -e "s:-O :\${CFLAGS} :" \
+ -e "s:LF2 = -s:LF2 = :" \
+ unix/Makefile \
diff --git a/patches/unzip/update_shared b/patches/unzip/update_shared
new file mode 100755
index 0000000..1dd8b2a
--- /dev/null
+++ b/patches/unzip/update_shared
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+ sed -i \
+ -e "s:-O3:\${CFLAGS}:" \
+ -e "s:CC=gcc :CC=gcc :" \
+ -e "s:LD=gcc :LD=\"gcc \${LDFLAGS} -lrcc\" :" \
+ -e "s:-O :\${CFLAGS} :" \
+ -e "s:LF2 = -s:LF2 = :" \
+ unix/Makefile \
diff --git a/patches/xmms-plugins/xmms-wma-csa1.tar.bz2 b/patches/xmms-plugins/xmms-wma-csa1.tar.bz2
new file mode 100644
index 0000000..de6968c
--- /dev/null
+++ b/patches/xmms-plugins/xmms-wma-csa1.tar.bz2
Binary files differ
diff --git a/patches/xmms/extra/xmms-ds-mpg123-wrongencoding.patch b/patches/xmms/extra/xmms-ds-mpg123-wrongencoding.patch
new file mode 100644
index 0000000..66a2100
--- /dev/null
+++ b/patches/xmms/extra/xmms-ds-mpg123-wrongencoding.patch
@@ -0,0 +1,157 @@
+diff -dPNur xmms-1.2.11-orig/Input/mpg123/id3_frame_text.c xmms-1.2.11/Input/mpg123/id3_frame_text.c
+--- xmms-1.2.11-orig/Input/mpg123/id3_frame_text.c 2008-04-11 15:44:34.000000000 +0200
++++ xmms-1.2.11/Input/mpg123/id3_frame_text.c 2008-04-11 15:52:25.000000000 +0200
+@@ -46,6 +46,7 @@
+ break;
+ case ID3_ENCODING_UTF16:
+ case ID3_ENCODING_UTF16BE:
++ case ID3_ENCODING_UTF16LE:
+ while (*text != 0 || *(text + 1) != 0)
+ {
+ text += 2;
+@@ -73,6 +74,8 @@
+ return xmms_charset_from_utf16(text);
+ case ID3_ENCODING_UTF16BE:
+ return xmms_charset_from_utf16be(text);
++ case ID3_ENCODING_UTF16LE:
++ return xmms_charset_from_utf16le(text);
+ default:
+ return NULL;
+ }
+@@ -88,6 +91,8 @@
+ */
+ gint8 id3_get_encoding(struct id3_frame *frame)
+ {
++ gint8 encoding;
++
+ /* Type check */
+ if (!id3_frame_is_text(frame) &&
+ frame->fr_desc->fd_id != ID3_WXXX &&
+@@ -106,7 +111,21 @@
+ if (id3_decompress_frame(frame) == -1)
+ return -1;
+
+- return *(gint8 *) frame->fr_data;
++ encoding = *(gint8 *) frame->fr_data;
++
++ switch (encoding) {
++ case ID3_ENCODING_ISO_8859_1:
++ case ID3_ENCODING_UTF8:
++ case ID3_ENCODING_UTF16:
++ case ID3_ENCODING_UTF16BE:
++ return encoding;
++ case ID3_ENCODING_UTF16LE:
++ printf("ID3V2 frame (%.4s) has invalid encoding (%u). Assuming UTF-16LE.\n", frame->fr_desc->fd_idstr?frame->fr_desc->fd_idstr:"UNKN", encoding);
++ return encoding;
++ default:
++ printf("ID3V2 frame (%.4s) has invalid encoding (%u). Assuming Latin1.\n", frame->fr_desc->fd_idstr?frame->fr_desc->fd_idstr:"UNKN", encoding);
++ return ID3_ENCODING_ISO_8859_1;
++ }
+ }
+
+
+@@ -269,6 +288,7 @@
+ else if (encoding == ID3_ENCODING_UTF8) ctext = xmms_charset_to_utf8(text);
+ else if (encoding == ID3_ENCODING_UTF16) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16");
+ else if (encoding == ID3_ENCODING_UTF16BE) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16BE");
++ else if (encoding == ID3_ENCODING_UTF16LE) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16LE");
+ else ctext = NULL;
+
+ if (ctext) text = ctext;
+@@ -433,6 +453,7 @@
+ else if (encoding == ID3_ENCODING_UTF8) ctext = xmms_charset_to_utf8(text);
+ else if (encoding == ID3_ENCODING_UTF16) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16");
+ else if (encoding == ID3_ENCODING_UTF16BE) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16BE");
++ else if (encoding == ID3_ENCODING_UTF16LE) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16LE");
+ else ctext = NULL;
+
+ if (ctext) text = ctext;
+@@ -453,11 +474,12 @@
+ *(gint8 *) frame->fr_raw_data = encoding;
+ memcpy((char*)frame->fr_raw_data + 1, xmms_rcc_get_language(), 3);
+
+- if ((encoding == ID3_ENCODING_UTF16)||(encoding == ID3_ENCODING_UTF16BE)) {
++ if ((encoding == ID3_ENCODING_UTF16)||(encoding == ID3_ENCODING_UTF16BE)||(encoding == ID3_ENCODING_UTF16LE)) {
+ int i;
+ lang = "Comments";
+ if (encoding == ID3_ENCODING_UTF16) cdata = xmms_charset_convert(lang, strlen(lang), NULL, "UTF-16");
+- else cdata = xmms_charset_convert(lang, strlen(lang), NULL, "UTF-16BE");
++ else if (encoding == ID3_ENCODING_UTF16BE) cdata = xmms_charset_convert(lang, strlen(lang), NULL, "UTF-16BE");
++ else cdata = xmms_charset_convert(lang, strlen(lang), NULL, "UTF-16LE");
+ memcpy((char *) frame->fr_raw_data + 4, cdata, 20);
+ g_free(cdata);
+ } else
+diff -dPNur xmms-1.2.11-orig/Input/mpg123/id3.h xmms-1.2.11/Input/mpg123/id3.h
+--- xmms-1.2.11-orig/Input/mpg123/id3.h 2008-04-11 15:44:34.000000000 +0200
++++ xmms-1.2.11/Input/mpg123/id3.h 2008-04-11 15:50:58.000000000 +0200
+@@ -141,6 +141,7 @@
+ #define ID3_ENCODING_UTF16 0x01
+ #define ID3_ENCODING_UTF16BE 0x02
+ #define ID3_ENCODING_UTF8 0x03
++#define ID3_ENCODING_UTF16LE 0x04
+
+ /*
+ * ID3 frame id numbers.
+@@ -312,7 +313,7 @@
+
+
+ #define ID3_TEXT_FRAME_ENCODING(frame) \
+- (*(guint8*)(frame)->fr_data)
++ id3_get_encoding(frame)
+
+ #define ID3_TEXT_FRAME_PTR(frame) \
+ ((char *)(frame)->fr_data + 1)
+diff -dPNur xmms-1.2.11-orig/libxmms/charset.c xmms-1.2.11/libxmms/charset.c
+--- xmms-1.2.11-orig/libxmms/charset.c 2008-04-10 22:49:57.000000000 +0200
++++ xmms-1.2.11/libxmms/charset.c 2008-04-11 15:50:21.000000000 +0200
+@@ -141,6 +141,14 @@
+ return xmms_charset_convert(string, utf16_strlen(string), "UTF-16BE", NULL);
+ }
+
++char *xmms_charset_from_utf16le(const unsigned char *string)
++{
++ if (!string)
++ return NULL;
++
++ return xmms_charset_convert(string, utf16_strlen(string), "UTF-16LE", NULL);
++}
++
+ char* xmms_charset_from_latin1(const char *string)
+ {
+ char *cstring;
+@@ -174,6 +182,9 @@
+ if (!strcmp(from, "UTF-16BE") && !to)
+ return xmms_charset_from_utf16be(string);
+
++ if (!strcmp(from, "UTF-16LE") && !to)
++ return xmms_charset_from_utf16le(string);
++
+ return g_strdup(string);
+ }
+
+@@ -275,6 +286,14 @@
+ return utf16_to_ascii(string, FALSE);
+ }
+
++char *xmms_charset_from_utf16le(const unsigned char *string)
++{
++ if (!string)
++ return NULL;
++
++ return utf16_to_ascii(string, TRUE);
++}
++
+ char* xmms_charset_from_latin1(const char *string)
+ {
+ char *cstring;
+diff -dPNur xmms-1.2.11-orig/libxmms/charset.h xmms-1.2.11/libxmms/charset.h
+--- xmms-1.2.11-orig/libxmms/charset.h 2008-04-10 22:49:57.000000000 +0200
++++ xmms-1.2.11/libxmms/charset.h 2008-04-11 15:49:47.000000000 +0200
+@@ -14,6 +14,7 @@
+ char* xmms_charset_from_utf8(const char *string);
+ char* xmms_charset_from_utf16(const unsigned char *string);
+ char* xmms_charset_from_utf16be(const unsigned char *string);
++char *xmms_charset_from_utf16le(const unsigned char *string);
+ char* xmms_charset_from_latin1(const char *string);
+
+ size_t utf16_strlen(const char *string);
diff --git a/patches/xmms/plugins/xmms-ds-mpg123-editor-keys.patch b/patches/xmms/plugins/xmms-ds-mpg123-editor-keys.patch
new file mode 100644
index 0000000..38a74e2
--- /dev/null
+++ b/patches/xmms/plugins/xmms-ds-mpg123-editor-keys.patch
@@ -0,0 +1,164 @@
+diff -dPNur rusxmms-new/Input/mpg123/fileinfo.c rusxmms-new-keys/Input/mpg123/fileinfo.c
+--- rusxmms-new/Input/mpg123/fileinfo.c 2005-07-17 11:46:05.000000000 +0200
++++ rusxmms-new-keys/Input/mpg123/fileinfo.c 2005-07-18 01:12:36.000000000 +0200
+@@ -31,6 +31,10 @@
+ #define MAX_STR_LEN 100
+ #define MAX_ENTRY_LEN2 1023
+
++#include <gdk/gdkkeysyms.h>
++#include <gdk/gdktypes.h>
++#include "../../xmms/xmms.h"
++
+ static GtkWidget *window = NULL;
+ static GtkWidget *notebook = NULL;
+ static GtkWidget *filename_entry, *id3v1_frame, *id3v2_frame;
+@@ -507,6 +511,106 @@
+ gtk_widget_destroy(w);
+ }
+
++static int restore_focus;
++static GtkWidget *save;
++
++
++static GtkWidget **widgets1[] = { &v1_title_entry, &v1_artist_entry, &v1_album_entry, &v1_comment_entry, &v1_year_entry, NULL };
++static GtkWidget **widgets2[] = { &v2_title_entry, &v2_artist_entry, &v2_album_entry, &v2_comment_entry, &v2_year_entry, &v2_composer_entry, &v2_orig_artist_entry, &v2_url_entry, &v2_encoded_by_entry, NULL };
++/* Info: gdktypes.h, gdkkeysyms.h */
++gboolean mpg123_keypress_cb(GtkWidget * w, GdkEventKey * event, gpointer close) {
++ gint pos;
++ GtkWidget ***widgets, *widget, *focused;
++
++ switch(event->keyval) {
++ case GDK_Return:
++ restore_focus=1;
++ gtk_signal_emit_by_name(GTK_OBJECT(save), "clicked", NULL);
++ gtk_signal_emit_by_name(GTK_OBJECT(close), "clicked", NULL);
++ return TRUE;
++ break;
++ case GDK_Escape:
++ restore_focus=1;
++ return TRUE;
++ break;
++ }
++
++ if (event->state&GDK_CONTROL_MASK) {
++ switch(event->keyval) {
++ case GDK_Left:
++ gtk_notebook_prev_page(GTK_NOTEBOOK(notebook));
++ pos = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
++ if (pos == 0) gtk_window_set_focus(GTK_WINDOW(window), *widgets2[0]);
++ else if (pos == 1) gtk_window_set_focus(GTK_WINDOW(window), *widgets1[0]);
++ gtk_window_activate_focus(GTK_WINDOW(window));
++ return TRUE;
++ break;
++ case GDK_Right:
++ gtk_notebook_next_page(GTK_NOTEBOOK(notebook));
++ pos = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
++ if (pos == 0) gtk_window_set_focus(GTK_WINDOW(window), *widgets2[0]);
++ else if (pos == 1) gtk_window_set_focus(GTK_WINDOW(window), *widgets1[0]);
++ gtk_window_activate_focus(GTK_WINDOW(window));
++ return TRUE;
++ break;
++ }
++ }
++ {
++ switch(event->keyval) {
++ case GDK_Page_Up:
++ pos = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
++
++ focused = GTK_WINDOW(window)->focus_widget;
++ if (pos == 1) widgets = widgets1;
++ else if (pos == 0) widgets = widgets2;
++ else return FALSE;
++
++ for (pos = 0; widgets[pos]; pos++) {
++ if (focused == *widgets[pos]) {
++ if (pos == 0) {
++ while (widgets[pos+1]) pos++;
++ widget = *widgets[pos];
++ } else widget = *widgets[pos - 1];
++
++ gtk_window_set_focus(GTK_WINDOW(window), widget);
++ return TRUE;
++ }
++ }
++ break;
++ case GDK_Page_Down:
++ case GDK_Tab:
++ pos = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
++
++ focused = GTK_WINDOW(window)->focus_widget;
++ if (pos == 1) widgets = widgets1;
++ else if (pos == 0) widgets = widgets2;
++ else return FALSE;
++
++ for (pos = 0; widgets[pos]; pos++) {
++ if (focused == *widgets[pos]) {
++ if (widgets[pos + 1]) widget = *widgets[pos + 1];
++ else widget = *widgets[0];
++
++ gtk_window_set_focus(GTK_WINDOW(window), widget);
++ return TRUE;
++ }
++ }
++
++ break;
++ }
++ }
++
++ return FALSE;
++}
++
++void gtk_widget_destroyed_focus(GtkWidget *widget, GtkWidget **widget_pointer) {
++ gtk_widget_destroyed(widget,widget_pointer);
++ if (restore_focus) {
++ gtk_widget_hide(playlistwin);
++ gtk_widget_show(playlistwin);
++ }
++}
++
+ void mpg123_file_info_box(char *filename)
+ {
+ int i;
+@@ -517,6 +621,8 @@
+ const char *emphasis[4];
+ const char *bool_label[2];
+
++ restore_focus = 0;
++
+ emphasis[0] = _("None");
+ emphasis[1] = _("50/15 ms");
+ emphasis[2] = "";
+@@ -529,15 +635,16 @@
+ GtkWidget *window_vbox,
+ *id3v1_vbox, *id3v2_vbox, *id3v1_frame_vbox, *id3v2_frame_vbox,
+ *mpeg_lvbox, *mpeg_rvbox, *mpeg_hbox, *mpeg_box, *mpeg_frame,
+- *bbox, *save, *close, *copy_to, *copy_from,
++ *bbox, *close, *copy_to, *copy_from,
+ *table, *label, *filename_hbox;
++ GtkAccelGroup *ag;
+
+ v1_labels_list = g_ptr_array_new();
+ v2_labels_list = g_ptr_array_new();
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+- gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window);
+- gtk_signal_connect(GTK_OBJECT(window), "key_press_event", file_info_box_keypress_cb, NULL);
++ gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed_focus), &window);
++// gtk_signal_connect(GTK_OBJECT(window),"key_press_event",file_info_box_keypress_cb, NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ window_vbox = gtk_vbox_new(FALSE,10);
+@@ -916,6 +1023,13 @@
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
+ gtk_box_pack_start(GTK_BOX(bbox), close, TRUE, TRUE, 5);
+
++ ag = gtk_accel_group_new();
++ gtk_accel_group_add(ag, GDK_Escape, 0, 0, GTK_OBJECT(close), "clicked");
++ gtk_accel_group_add(ag, GDK_Return, 0, 0, GTK_OBJECT(save), "clicked");
++ gtk_window_add_accel_group(GTK_WINDOW(window), ag);
++
++ gtk_signal_connect(GTK_OBJECT(window), "key_press_event", GTK_SIGNAL_FUNC(mpg123_keypress_cb), close);
++
+ gtk_container_add(GTK_CONTAINER(window), window_vbox);
+ gtk_widget_show_all(window);
+ }
diff --git a/patches/xmms/plugins/xmms-ds-mpg123-editor.patch b/patches/xmms/plugins/xmms-ds-mpg123-editor.patch
new file mode 100644
index 0000000..a4afb70
--- /dev/null
+++ b/patches/xmms/plugins/xmms-ds-mpg123-editor.patch
@@ -0,0 +1,202 @@
+diff -dPNur xmms-1.2.10/Input/mpg123/fileinfo.c xmms-1.2.10-new/Input/mpg123/fileinfo.c
+--- rusxmms/Input/mpg123/fileinfo.c 2005-07-17 01:54:55.000000000 +0200
++++ rusxmms-new/Input/mpg123/fileinfo.c 2005-07-17 11:46:05.000000000 +0200
+@@ -24,6 +24,7 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <libxmms/xentry.h>
++#include <libxmms/rcc.h>
+ #include <gdk/gdkkeysyms.h>
+ #include "mpg123.h"
+
+@@ -60,19 +61,33 @@
+
+ static void set_entry_tag_v1(GtkEntry * entry, const char * tag, int length)
+ {
+- char *text = g_strchomp(g_strndup(tag, length));
++ char *text;
++
++ text = xmms_rcc_sized_recode(XMMS_RCC_ID3, XMMS_RCC_CTYPE, tag, length);
++ if (!text) text = g_strchomp(g_strndup(tag, length));
++
+ gtk_entry_set_text(entry, text);
+ g_free(text);
+ }
+
+ static void get_entry_tag_v1(GtkEntry * entry, char * tag, int length)
+ {
++ gchar *ctext;
++
++ ctext = xmms_rcc_recode(XMMS_RCC_CTYPE, XMMS_RCC_ID3, gtk_entry_get_text(entry));
++
++ if (ctext) {
++ strncpy(tag, ctext, length);
++ free(ctext);
++ } else
+ strncpy(tag, gtk_entry_get_text(entry), length);
+ }
+
+ void copy_entry_tag_v1(GtkEntry * src, GtkEntry * dest, int length)
+ {
+- set_entry_tag_v1(dest, gtk_entry_get_text(src), length);
++ char *text = g_strchomp(g_strndup(gtk_entry_get_text(src), length));
++ gtk_entry_set_text(dest, text);
++ g_free(text);
+ return;
+ }
+
+@@ -497,6 +512,7 @@
+ int i;
+ struct id3v1tag_t id3v1tag;
+ FILE *fh;
++ gchar *cfilename;
+ char *tmp, *title;
+ const char *emphasis[4];
+ const char *bool_label[2];
+@@ -908,6 +924,9 @@
+ g_free(current_filename);
+ current_filename = g_strdup(filename);
+
++ cfilename = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_OUT, filename);
++ if (cfilename) filename=cfilename;
++
+ title = g_strdup_printf(_("File Info - %s"), g_basename(filename));
+ gtk_window_set_title(GTK_WINDOW(window), title);
+ g_free(title);
+@@ -922,6 +941,8 @@
+ gtk_entry_set_text(GTK_ENTRY(v2_title_entry), title);
+ g_free(title);
+
++ if (cfilename) g_free(cfilename);
++
+ gtk_entry_set_text(GTK_ENTRY(v1_artist_entry), "");
+ gtk_entry_set_text(GTK_ENTRY(v1_album_entry), "");
+ gtk_entry_set_text(GTK_ENTRY(v1_year_entry), "");
+diff -dPNur xmms-1.2.10/Input/mpg123/id3_frame_text.c xmms-1.2.10-new/Input/mpg123/id3_frame_text.c
+--- xmms-1.2.10/Input/mpg123/id3_frame_text.c 2005-08-10 03:20:03.000000000 +0200
++++ xmms-1.2.10-new/Input/mpg123/id3_frame_text.c 2005-08-10 03:29:40.000000000 +0200
+@@ -28,6 +28,7 @@
+ #include "id3_header.h"
+
+ #include "libxmms/charset.h"
++#include "libxmms/rcc.h"
+
+ /* For extern mpg123_cfg */
+ #include "mpg123.h"
+@@ -247,6 +248,9 @@
+ */
+ int id3_set_text(struct id3_frame *frame, char *text)
+ {
++ char *ctext;
++ gint8 encoding;
++
+ /* Type check */
+ if (frame->fr_desc->fd_idstr[0] != 'T')
+ return -1;
+@@ -256,18 +260,36 @@
+ */
+ id3_frame_clear_data(frame);
+
++
++ /*
++ * Recoding.
++ */
++ encoding = (gint8)xmms_rcc_get_id3v2_encoding();
++ if (encoding == ID3_ENCODING_ISO_8859_1) ctext = xmms_rcc_recode(XMMS_RCC_CTYPE, XMMS_RCC_ID3V2, text);
++ else if (encoding == ID3_ENCODING_UTF8) ctext = xmms_charset_to_utf8(text);
++ else if (encoding == ID3_ENCODING_UTF16) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16");
++ else if (encoding == ID3_ENCODING_UTF16BE) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16BE");
++ else ctext = NULL;
++
++ if (ctext) text = ctext;
++
+ /*
+ * Allocate memory for new data.
+ */
++ if ((encoding == ID3_ENCODING_UTF16)||(encoding == ID3_ENCODING_UTF16BE))
++ frame->fr_raw_size = utf16_strlen(text) + 2;
++ else
+ frame->fr_raw_size = strlen(text) + 1;
+ frame->fr_raw_data = g_malloc(frame->fr_raw_size + 1);
+
+ /*
+ * Copy contents.
+ */
+- *(gint8 *) frame->fr_raw_data = ID3_ENCODING_ISO_8859_1;
++ *(gint8 *) frame->fr_raw_data = encoding;
+ memcpy((char *) frame->fr_raw_data + 1, text, frame->fr_raw_size);
+
++ if (ctext) free(ctext);
++
+ frame->fr_altered = 1;
+ frame->fr_owner->id3_altered = 1;
+
+@@ -389,7 +411,10 @@
+ */
+ int id3_set_comment(struct id3_frame *frame, char *text)
+ {
++ char *ctext, *cdata;
++ const char *lang;
+ int *intp;
++ gint8 encoding;
+
+ /* Type check */
+ if (frame->fr_desc->fd_id != ID3_COMM)
+@@ -401,8 +426,23 @@
+ id3_frame_clear_data(frame);
+
+ /*
++ * Recoding.
++ */
++ encoding = (gint8)xmms_rcc_get_id3v2_encoding();
++ if (encoding == ID3_ENCODING_ISO_8859_1) ctext = xmms_rcc_recode(XMMS_RCC_CTYPE, XMMS_RCC_ID3V2, text);
++ else if (encoding == ID3_ENCODING_UTF8) ctext = xmms_charset_to_utf8(text);
++ else if (encoding == ID3_ENCODING_UTF16) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16");
++ else if (encoding == ID3_ENCODING_UTF16BE) ctext = xmms_charset_convert(text, strlen(text), NULL, "UTF-16BE");
++ else ctext = NULL;
++
++ if (ctext) text = ctext;
++
++ /*
+ * Allocate memory for new data.
+ */
++ if ((encoding == ID3_ENCODING_UTF16)||(encoding == ID3_ENCODING_UTF16BE))
++ frame->fr_raw_size = 25 + utf16_strlen(text);
++ else
+ frame->fr_raw_size = 13 + strlen(text);
+ frame->fr_raw_data = g_malloc(frame->fr_raw_size + 1); /* <encode>XXXComments\0<comment><\0>
+
+@@ -410,18 +450,29 @@
+ * block, so don't waste time with a calloc()
+ */
+
+- ((guint8 *)frame->fr_raw_data)[0] = ID3_ENCODING_ISO_8859_1;
+- ((guint8 *)frame->fr_raw_data)[1] = 0x58;
+- ((guint8 *)frame->fr_raw_data)[2] = 0x58;
+- ((guint8 *)frame->fr_raw_data)[3] = 0x58;
++ *(gint8 *) frame->fr_raw_data = encoding;
++ memcpy((char*)frame->fr_raw_data + 1, xmms_rcc_get_language(), 3);
+
++ if ((encoding == ID3_ENCODING_UTF16)||(encoding == ID3_ENCODING_UTF16BE)) {
++ int i;
++ lang = "Comments";
++ if (encoding == ID3_ENCODING_UTF16) cdata = xmms_charset_convert(lang, strlen(lang), NULL, "UTF-16");
++ else cdata = xmms_charset_convert(lang, strlen(lang), NULL, "UTF-16BE");
++ memcpy((char *) frame->fr_raw_data + 4, cdata, 20);
++ g_free(cdata);
++ } else
+ memcpy((char *) frame->fr_raw_data + 4, "Comments", 9);
+
+ /*
+ * Copy contents.
+ */
++ if ((encoding == ID3_ENCODING_UTF16)||(encoding == ID3_ENCODING_UTF16BE))
++ memcpy((char *) frame->fr_raw_data + 24, text, utf16_strlen(text) + 2);
++ else
+ memcpy((char *) frame->fr_raw_data + 13, text, strlen(text) + 1);
+
++ if (ctext) free(ctext);
++
+ frame->fr_altered = 1;
+ frame->fr_owner->id3_altered = 1;
+
diff --git a/patches/xmms/plugins/xmms-ds-mpg123.patch b/patches/xmms/plugins/xmms-ds-mpg123.patch
new file mode 100644
index 0000000..fc9c42e
--- /dev/null
+++ b/patches/xmms/plugins/xmms-ds-mpg123.patch
@@ -0,0 +1,20 @@
+diff -dPNur xmms-1.2.11/Input/mpg123/mpg123.c xmms-1.2.11-new/Input/mpg123/mpg123.c
+--- xmms-1.2.11/Input/mpg123/mpg123.c 2007-11-25 00:04:27.000000000 +0100
++++ xmms-1.2.11-new/Input/mpg123/mpg123.c 2007-11-25 01:18:57.000000000 +0100
+@@ -3,6 +3,7 @@
+ #include "libxmms/configfile.h"
+ #include "libxmms/titlestring.h"
+ #include "libxmms/charset.h"
++#include "libxmms/rcc.h"
+ #include <string.h>
+ #include <stdlib.h>
+ #include <pthread.h>
+@@ -496,6 +497,8 @@
+ /*
+ * Format according to filename.
+ */
++ ret = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_CTYPE, g_basename(filename));
++ if (!ret)
+ ret = g_strdup(g_basename(filename));
+ if (extname(ret) != NULL)
+ *(extname(ret) - 1) = '\0'; /* removes period */
diff --git a/patches/xmms/plugins/xmms-ds-vorbis-editor-keys.patch b/patches/xmms/plugins/xmms-ds-vorbis-editor-keys.patch
new file mode 100644
index 0000000..bf59951
--- /dev/null
+++ b/patches/xmms/plugins/xmms-ds-vorbis-editor-keys.patch
@@ -0,0 +1,78 @@
+diff -dPNur xmms-1.2.11/Input/vorbis/fileinfo.c xmms-1.2.11-new/Input/vorbis/fileinfo.c
+--- xmms-1.2.11/Input/vorbis/fileinfo.c 2007-11-25 01:23:31.000000000 +0100
++++ xmms-1.2.11-new/Input/vorbis/fileinfo.c 2007-11-25 01:24:01.000000000 +0100
+@@ -39,6 +39,9 @@
+ #include "libxmms/charset.h"
+ #include <xmms/i18n.h>
+
++#include "../../xmms/xmms.h"
++#include <gdk/gdkkeysyms.h>
++
+ #include "vorbis.h"
+ #include "vcedit.h"
+
+@@ -444,6 +447,28 @@
+ }
+
+ /***********************************************************************/
++static int restore_focus;
++
++gboolean vorbis_keypress_cb(GtkWidget * w, GdkEventKey * event, gpointer save) {
++ switch(event->keyval) {
++ case GDK_Return:
++ restore_focus=1;
++ gtk_signal_emit_by_name(GTK_OBJECT(save), "clicked", NULL);
++ break;
++ case GDK_Escape:
++ restore_focus=1;
++ break;
++ }
++ return TRUE;
++}
++
++void gtk_widget_destroyed_focus(GtkWidget *widget, GtkWidget **widget_pointer) {
++ gtk_widget_destroyed(widget,widget_pointer);
++ if (restore_focus) {
++ gtk_widget_hide(playlistwin);
++ gtk_widget_show(playlistwin);
++ }
++}
+
+ void vorbis_file_info_box(char *fn)
+ {
+@@ -465,6 +490,8 @@
+
+ g_free(vte.filename);
+ vte.filename = g_strdup(fn);
++
++ restore_focus = 0;
+
+ if (!window)
+ {
+@@ -472,11 +499,12 @@
+ GtkWidget *hbox, *label, *filename_hbox, *vbox, *left_vbox;
+ GtkWidget *table, *bbox, *cancel_button;
+ GtkWidget *save_button, *remove_button;
++ GtkAccelGroup *ag;
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
+ gtk_signal_connect(GTK_OBJECT(window), "destroy",
+- GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window);
++ GTK_SIGNAL_FUNC(gtk_widget_destroyed_focus), &window);
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ keypress_cb, NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+@@ -809,6 +837,12 @@
+ FALSE, 0);
+
+ gtk_widget_show_all(window);
++
++ ag = gtk_accel_group_new();
++ gtk_accel_group_add(ag, GDK_Escape, 0, 0, GTK_OBJECT(cancel_button), "clicked");
++ gtk_accel_group_add(ag, GDK_Return, 0, 0, GTK_OBJECT(save_button), "clicked");
++ gtk_window_add_accel_group(GTK_WINDOW(window), ag);
++ gtk_signal_connect(GTK_OBJECT(window),"key_press_event",GTK_SIGNAL_FUNC(vorbis_keypress_cb),save_button);
+ } else
+ gdk_window_raise(window->window);
+
diff --git a/patches/xmms/plugins/xmms-ds-vorbis-editor.patch b/patches/xmms/plugins/xmms-ds-vorbis-editor.patch
new file mode 100644
index 0000000..47a7ba9
--- /dev/null
+++ b/patches/xmms/plugins/xmms-ds-vorbis-editor.patch
@@ -0,0 +1,51 @@
+diff -dPNur xmms-1.2.11/Input/vorbis/fileinfo.c xmms-1.2.11-new/Input/vorbis/fileinfo.c
+--- xmms-1.2.11/Input/vorbis/fileinfo.c 2007-11-25 00:04:27.000000000 +0100
++++ xmms-1.2.11-new/Input/vorbis/fileinfo.c 2007-11-25 01:20:57.000000000 +0100
+@@ -34,6 +34,7 @@
+ #include <vorbis/codec.h>
+ #include <vorbis/vorbisfile.h>
+
++#include "libxmms/rcc.h"
+ #include "libxmms/util.h"
+ #include "libxmms/charset.h"
+ #include <xmms/i18n.h>
+@@ -451,6 +452,7 @@
+ char *description, *version, *isrc, *copyright, *organization;
+ char *location, *vendor = "N/A";
+ char *rg_track_gain, *rg_album_gain, *rg_track_peak, *rg_album_peak;
++ gchar *cfilename;
+
+ int time, minutes, seconds, bitrate, avgbitrate, rate, channels;
+ int filesize, i;
+@@ -931,6 +933,11 @@
+ gtk_entry_set_text(GTK_ENTRY(isrc_entry), isrc);
+ gtk_entry_set_text(GTK_ENTRY(location_entry), location);
+ #endif
++ cfilename = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_CTYPE, vte.filename);
++ if (cfilename) {
++ gtk_entry_set_text(GTK_ENTRY(filename_entry), cfilename);
++ g_free(cfilename);
++ } else
+ gtk_entry_set_text(GTK_ENTRY(filename_entry), vte.filename);
+ gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1);
+
+diff -dPNur xmms-1.2.11/Input/vorbis/vorbis.c xmms-1.2.11-new/Input/vorbis/vorbis.c
+--- xmms-1.2.11/Input/vorbis/vorbis.c 2007-11-25 00:04:27.000000000 +0100
++++ xmms-1.2.11-new/Input/vorbis/vorbis.c 2007-11-25 01:20:57.000000000 +0100
+@@ -46,6 +46,7 @@
+ #include "xmms/plugin.h"
+ #include "libxmms/util.h"
+ #include "libxmms/configfile.h"
++#include "libxmms/rcc.h"
+ #include "libxmms/titlestring.h"
+ #include "libxmms/charset.h"
+ #include <xmms/i18n.h>
+@@ -754,6 +755,8 @@
+ if (!vorbis_is_streaming)
+ {
+ char *tmp;
++ displaytitle = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_OUT, g_basename(fn));
++ if (!displaytitle)
+ displaytitle = g_strdup(g_basename(fn));
+ if ((tmp = strrchr(displaytitle, '.')) != NULL)
+ *tmp = '\0';
diff --git a/patches/xmms/xmms-ds-playlist.patch b/patches/xmms/xmms-ds-playlist.patch
new file mode 100644
index 0000000..b72c8d0
--- /dev/null
+++ b/patches/xmms/xmms-ds-playlist.patch
@@ -0,0 +1,526 @@
+diff -dPNur xmms-1.2.11/xmms/input.c xmms-1.2.11-new/xmms/input.c
+--- xmms-1.2.11/xmms/input.c 2005-05-15 02:01:21.000000000 +0200
++++ xmms-1.2.11-new/xmms/input.c 2008-10-27 18:14:08.000000000 +0100
+@@ -22,6 +22,7 @@
+ #include "libxmms/titlestring.h"
+ #include "libxmms/util.h"
+ #include "libxmms/xentry.h"
++#include "libxmms/rcc.h"
+
+ static pthread_mutex_t vis_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+@@ -372,8 +373,12 @@
+
+ (*title) = xmms_get_titlestring(xmms_get_gentitle_format(),
+ input);
+- if ( (*title) == NULL )
++ if ( (*title) == NULL ) {
++ (*title) = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_CTYPE, input->file_name);
++ if (!*title)
+ (*title) = g_strdup(input->file_name);
++ }
++
+ (*length) = -1;
+ g_free(temp);
+ g_free(input);
+diff -dPNur xmms-1.2.11/xmms/main.c xmms-1.2.11-new/xmms/main.c
+--- xmms-1.2.11/xmms/main.c 2006-07-16 15:40:04.000000000 +0200
++++ xmms-1.2.11-new/xmms/main.c 2008-10-27 18:14:08.000000000 +0100
+@@ -36,6 +36,7 @@
+ #include "libxmms/xmmsctrl.h"
+ #include "libxmms/util.h"
+ #include "libxmms/dirbrowser.h"
++#include "libxmms/rcc.h"
+ #include "xmms_mini.xpm"
+
+ #define RANDTABLE_SIZE 128
+@@ -899,6 +900,7 @@
+ gtk_timeout_remove(mainwin_timeout_tag);
+ util_set_cursor(NULL);
+ save_config();
++ xmms_rcc_free();
+ cleanup_ctrlsocket();
+ playlist_stop_get_info_thread();
+ playlist_clear();
+@@ -1036,8 +1038,14 @@
+
+ void mainwin_lock_info_text(char *text)
+ {
++ gchar *ctext;
++ ctext = xmms_rcc_recode(XMMS_RCC_CTYPE, XMMS_RCC_OUT, text);
++ if (ctext) text=ctext;
++
+ mainwin_info_text_locked = TRUE;
+ textbox_set_text(mainwin_info, text);
++
++ if (ctext) g_free(ctext);
+ }
+
+ void mainwin_release_info_text(void)
+@@ -1695,9 +1703,10 @@
+ int match = 0;
+ char *title, *filename;
+
+- title = ((PlaylistEntry *) playlist->data)->title;
+- filename = ((PlaylistEntry *) playlist->data)->filename;
+-
++ title = playlist_check_entrytitle((PlaylistEntry *) playlist->data);
++ filename = xmms_rcc_get(XMMS_RCC_OUT, ((PlaylistEntry *) playlist->data)->fnstring);
++ if (!filename) filename = g_strdup(((PlaylistEntry *) playlist->data)->filename);
++
+ if (title)
+ desc_buf[1] = title;
+ else if (strchr(filename, '/'))
+@@ -1749,7 +1758,7 @@
+ */
+ match = mainwin_jump_to_file_match(song, words, nw);
+ }
+-
++
+ if (match)
+ {
+ int row, queue_pos, *data_buf;
+@@ -1772,6 +1781,10 @@
+ row_to_select = row;
+ }
+
++ g_free(filename);
++ g_free(title);
++
++
+ songnr++;
+ playlist = playlist->next;
+ }
+@@ -2072,8 +2085,10 @@
+ int row, *data_buf;
+ char *title, *filename, *tmp_buf, *desc_buf[2];
+
+- title = ((PlaylistEntry *) queue->data)->title;
+- filename = ((PlaylistEntry *) queue->data)->filename;
++ title = playlist_check_entrytitle((PlaylistEntry *) queue->data);
++ filename = xmms_rcc_get(XMMS_RCC_OUT, ((PlaylistEntry *) queue->data)->fnstring);
++ if (!filename) filename = g_strdup(((PlaylistEntry *) queue->data)->filename);
++
+ if (title)
+ desc_buf[1] = title;
+ else if (strchr(filename, '/'))
+@@ -2086,6 +2101,9 @@
+ row = gtk_clist_append(GTK_CLIST(qlist), desc_buf);
+ g_free(tmp_buf);
+
++ g_free(filename);
++ g_free(title);
++
+ data_buf = g_malloc(sizeof (int));
+ *data_buf = pos;
+ gtk_clist_set_row_data_full(qlist, row, data_buf, g_free);
+@@ -4217,6 +4235,7 @@
+ #endif
+
+ read_config();
++ xmms_rcc_init();
+
+ #if defined(HAVE_SCHED_SETSCHEDULER) && defined(HAVE_SCHED_GET_PRIORITY_MAX)
+ if (cfg.use_realtime)
+diff -dPNur xmms-1.2.11/xmms/playlist.c xmms-1.2.11-new/xmms/playlist.c
+--- xmms-1.2.11/xmms/playlist.c 2007-11-16 22:51:30.000000000 +0100
++++ xmms-1.2.11-new/xmms/playlist.c 2008-10-27 18:14:31.000000000 +0100
+@@ -20,6 +20,8 @@
+ #include "xmms.h"
+ #include <time.h>
+ #include "libxmms/util.h"
++#include <locale.h>
++#include "libxmms/rcc.h"
+ #include <sys/stat.h>
+ #include <unistd.h>
+
+@@ -91,6 +93,8 @@
+ entry = node->data;
+ if (entry->filename)
+ g_free(entry->filename);
++ if (entry->fnstring)
++ g_free(entry->fnstring);
+ if (entry->title)
+ g_free(entry->title);
+ g_free(entry);
+@@ -166,6 +170,8 @@
+
+ if (entry->filename)
+ g_free(entry->filename);
++ if (entry->fnstring)
++ g_free(entry->fnstring);
+ if (entry->title)
+ g_free(entry->title);
+ shuffle_list = g_list_remove(shuffle_list, entry);
+@@ -280,9 +286,17 @@
+ PlaylistEntry *entry;
+
+ entry = g_malloc0(sizeof (PlaylistEntry));
++
+ entry->filename = g_strdup(filename);
++ entry->fnstring = xmms_rcc_put(XMMS_RCC_FS, filename);
++ if (!entry->fnstring) entry->fnstring = g_strdup(filename);
++
+ if (title)
++ {
++ entry->title = xmms_rcc_put(XMMS_RCC_CTYPE, title);
++ if (!entry->title)
+ entry->title = g_strdup(title);
++ }
+ entry->length = len;
+
+ PL_LOCK();
+@@ -624,6 +638,8 @@
+ if (playlist_position)
+ {
+ g_free(playlist_position->title);
++ playlist_position->title = xmms_rcc_put(XMMS_RCC_CTYPE, title);
++ if (!playlist_position->title)
+ playlist_position->title = g_strdup(title);
+ playlist_position->length = length;
+ }
+@@ -1015,6 +1031,7 @@
+ char *playlist_get_info_text(void)
+ {
+ char *text, *title, *tmp, *numbers, *length;
++ char *ctitle;
+
+ PL_LOCK();
+ if (!playlist_position)
+@@ -1023,10 +1040,20 @@
+ return NULL;
+ }
+
+- if (playlist_position->title)
++ if (playlist_position->title) {
++ ctitle = xmms_rcc_get(XMMS_RCC_OUT, playlist_position->title);
++ if (ctitle) title = ctitle;
++ else
+ title = playlist_position->title;
+- else
++ } else {
++ ctitle = xmms_rcc_get(XMMS_RCC_OUT, playlist_position->fnstring);
++ if (ctitle) {
++ title = g_strdup(g_basename(ctitle));
++ g_free(ctitle);
++ ctitle = title;
++ } else
+ title = g_basename(playlist_position->filename);
++ }
+
+ /*
+ * If the user don't want numbers in the playlist, don't
+@@ -1048,6 +1075,7 @@
+ text = g_strdup_printf("%s%s%s", numbers, title, length);
+ g_free(numbers);
+ g_free(length);
++ if (ctitle) g_free(ctitle);
+
+ PL_UNLOCK();
+
+@@ -1083,6 +1111,7 @@
+ {
+ GList *node;
+ FILE *file;
++ gchar *ctitle, *cfn;
+
+ if ((file = fopen(filename, "w")) == NULL)
+ return FALSE;
+@@ -1101,10 +1130,12 @@
+ while (node)
+ {
+ PlaylistEntry *entry = node->data;
++ if (!strstr(entry->filename,"://")) cfn = xmms_rcc_fs2pl(entry->fnstring, entry->filename);
++ else cfn=NULL;
+ if (is_pls)
+ fprintf(file, "File%d=%s\n",
+ g_list_position(playlist, node) + 1,
+- entry->filename);
++ cfn?cfn:entry->filename);
+ else
+ {
+ if (entry->title && cfg.use_pl_metadata)
+@@ -1116,11 +1147,14 @@
+ else
+ seconds = -1;
+
++ ctitle = xmms_rcc_get(XMMS_RCC_PL, entry->title);
+ fprintf(file, "#EXTINF:%d,%s\n",
+- seconds, entry->title);
++ seconds, ctitle?ctitle:entry->title);
++ if (ctitle) g_free(ctitle);
+ }
+- fprintf(file, "%s\n", entry->filename);
++ fprintf(file, "%s\n", cfn?cfn:entry->filename);
+ }
++ if (cfn) g_free(cfn);
+ node = g_list_next(node);
+ }
+ PL_UNLOCK();
+@@ -1151,16 +1185,32 @@
+ *temp = '\0';
+ else
+ {
++ if ((!strstr(filename,"://"))&&(!strstr(playlist_name, "://"))) {
++ temp = xmms_rcc_fs(XMMS_RCC_PLFS, XMMS_RCC_FS, NULL, NULL, filename);
++ if (temp) filename = temp;
++ } else temp = NULL;
+ __playlist_ins_with_info(filename, pos, title, len);
++ if (temp) g_free(temp);
+ return;
+ }
++ if ((!strstr(filename,"://"))&&(!strstr(playlist_name, "://"))) {
++ temp = xmms_rcc_fs(XMMS_RCC_PLFS, XMMS_RCC_FS, path, path, filename);
++ if (temp) filename = temp;
++ } else temp = NULL;
++ if (!temp)
+ temp = g_strdup_printf("%s/%s", path, filename);
+ __playlist_ins_with_info(temp, pos, title, len);
+ g_free(temp);
+ g_free(path);
+ }
+- else
++ else {
++ if ((filename[0] == '/')&&(!strstr(playlist_name, "://"))) {
++ temp = xmms_rcc_fs(XMMS_RCC_PLFS, XMMS_RCC_FS, NULL, NULL, filename);
++ if (temp) filename = temp;
++ } else temp = NULL;
+ __playlist_ins_with_info(filename, pos, title, len);
++ if (temp) g_free(temp);
++ }
+ }
+
+ static void parse_extm3u_info(char *info, char **title, int *length)
+@@ -1182,6 +1232,10 @@
+ *length *= 1000;
+ if ((str = strchr(info, ',')) != NULL)
+ {
++ if (*str)
++ while ((*(str+1)==' ')||(*(str+1)=='\t')) str++; /* g_strstrip removes leading and ending whitespaces */
++ *title = xmms_rcc_put(XMMS_RCC_PL, str + 1);
++ if (!*title)
+ *title = g_strdup(str + 1);
+ g_strstrip(*title);
+ if (strlen(*title) < 1)
+@@ -1210,7 +1264,7 @@
+ line = read_ini_string(filename, "playlist", "NumberOfEntries");
+ if (line == NULL)
+ return 0;
+-
++
+ noe = atoi(line);
+ g_free(line);
+
+@@ -1372,9 +1426,27 @@
+ return ret;
+ }
+
++gchar* playlist_check_entrytitle(PlaylistEntry *entry) {
++ gchar *title, *fn;
++
++ if (!entry) return NULL;
++
++ title = xmms_rcc_get(XMMS_RCC_OUT, entry->title);
++ if (!title) {
++ fn = xmms_rcc_get(XMMS_RCC_OUT, entry->fnstring);
++ if (fn) {
++ title = g_strdup(g_basename(fn));
++ g_free(fn);
++ } else title = g_strdup(g_basename(entry->filename));
++ }
++
++ return title;
++}
++
+ char * playlist_get_songtitle(int pos)
+ {
+ char *title = NULL, *filename;
++ char *ctitle;
+ PlaylistEntry *entry;
+ GList *node;
+
+@@ -1396,19 +1468,30 @@
+
+ if (entry->title == NULL && entry->length == -1)
+ {
+- if (playlist_get_info_entry(entry))
++ if (playlist_get_info_entry(entry)&&(entry->title)) {
++ title = xmms_rcc_get(XMMS_RCC_OUT, entry->title);
++ if (!title)
+ title = g_strdup(entry->title);
++ }
+
+ PL_UNLOCK();
+ }
+ else
+ {
++ title = xmms_rcc_get(XMMS_RCC_OUT, entry->title);
++ if (!title)
+ title = g_strdup(entry->title);
+ PL_UNLOCK();
+ }
+
+- if (title == NULL)
++ if (title == NULL) {
++ ctitle = xmms_rcc_get(XMMS_RCC_OUT, entry->filename);
++ if (ctitle) {
++ title = g_strdup(g_basename(ctitle));
++ g_free(ctitle);
++ } else
+ title = g_strdup(g_basename(filename));
++ }
+
+ g_free(filename);
+
+@@ -1453,36 +1536,41 @@
+
+ static int playlist_sort_by_title_cmpfunc(PlaylistEntry * a, PlaylistEntry * b)
+ {
+- char *a_title, *b_title;
++ const char *a_title, *b_title;
+
+ if (a->title)
+- a_title = a->title;
++ a_title = xmms_rcc_string(a->title);
+ else
+ {
+- if (strrchr(a->filename, '/'))
+- a_title = strrchr(a->filename, '/') + 1;
++ if (strrchr(xmms_rcc_string(a->fnstring), '/'))
++ a_title = strrchr(xmms_rcc_string(a->fnstring), '/') + 1;
+ else
+- a_title = a->filename;
++ a_title = xmms_rcc_string(a->filename);
+ }
+
+ if (b->title)
+- b_title = b->title;
++ b_title = xmms_rcc_string(b->title);
+ else
+ {
+- if (strrchr(a->filename, '/'))
+- b_title = strrchr(b->filename, '/') + 1;
++ if (strrchr(xmms_rcc_string(a->fnstring), '/'))
++ b_title = strrchr(xmms_rcc_string(b->fnstring), '/') + 1;
+ else
+- b_title = b->filename;
+-
++ b_title = xmms_rcc_string(b->filename);
+ }
+- return strcasecmp(a_title, b_title);
++ return strcoll(a_title, b_title);
+ }
+
+ void playlist_sort_by_title(void)
+ {
++ char *locale;
++ locale = setlocale(LC_COLLATE,"en_US.UTF-8");
++ playlist_select_all(1);
++ playlist_read_info_selection();
++ playlist_select_all(0);
+ PL_LOCK();
+ playlist = g_list_sort(playlist, (GCompareFunc) playlist_sort_by_title_cmpfunc);
+ PL_UNLOCK();
++ setlocale(LC_COLLATE,locale);
+ }
+
+ static int playlist_sort_by_filename_cmpfunc(PlaylistEntry * a, PlaylistEntry * b)
+@@ -1640,9 +1728,13 @@
+
+ void playlist_sort_selected_by_title(void)
+ {
++ char *locale;
++ locale = setlocale(LC_COLLATE,"en_US.UTF-8");
++ playlist_read_info_selection();
+ PL_LOCK();
+ playlist = playlist_sort_selected(playlist, (GCompareFunc) playlist_sort_by_title_cmpfunc);
+ PL_UNLOCK();
++ setlocale(LC_COLLATE,locale);
+ }
+
+ void playlist_sort_selected_by_filename(void)
+@@ -1859,6 +1951,8 @@
+ return FALSE;
+
+ /* entry is still around */
++ entry->title = xmms_rcc_put(XMMS_RCC_CTYPE, temp_title);
++ if (!entry->title)
+ entry->title = temp_title;
+ entry->length = temp_length;
+
+diff -dPNur xmms-1.2.11/xmms/playlist.h xmms-1.2.11-new/xmms/playlist.h
+--- xmms-1.2.11/xmms/playlist.h 2007-11-16 22:51:30.000000000 +0100
++++ xmms-1.2.11-new/xmms/playlist.h 2008-10-27 18:14:08.000000000 +0100
+@@ -23,6 +23,7 @@
+ typedef struct
+ {
+ gchar *filename;
++ gchar *fnstring;
+ gchar *title;
+ gint length;
+ gboolean selected;
+@@ -86,6 +87,7 @@
+ void playlist_fileinfo(gint pos);
+ void playlist_delete_index(glong index);
+ void playlist_delete_filenames(GList *filenames);
++gchar* playlist_check_entrytitle(PlaylistEntry *entry);
+ gchar* playlist_get_filename(gint pos);
+ gchar* playlist_get_songtitle(gint pos);
+ gint playlist_get_songtime(gint pos);
+diff -dPNur xmms-1.2.11/xmms/playlist_list.c xmms-1.2.11-new/xmms/playlist_list.c
+--- xmms-1.2.11/xmms/playlist_list.c 2003-06-11 20:44:17.000000000 +0200
++++ xmms-1.2.11-new/xmms/playlist_list.c 2008-10-27 18:14:08.000000000 +0100
+@@ -451,10 +451,8 @@
+ else
+ gdk_gc_set_foreground(gc, get_skin_color(SKIN_PLEDIT_NORMAL));
+
+- if (entry->title)
+- title = entry->title;
+- else
+- title = g_basename(entry->filename);
++
++ title = playlist_check_entrytitle(entry);
+
+ pos = playlist_get_queue_position(entry);
+
+@@ -497,6 +495,8 @@
+ playlist_list_draw_string(pl, playlist_list_font,
+ i - pl->pl_first, tw, text);
+ g_free(text);
++
++ g_free(title);
+ }
+ PL_UNLOCK();
+ }
+diff -dPNur xmms-1.2.11/xmms/prefswin.c xmms-1.2.11-new/xmms/prefswin.c
+--- xmms-1.2.11/xmms/prefswin.c 2007-11-16 22:51:30.000000000 +0100
++++ xmms-1.2.11-new/xmms/prefswin.c 2008-10-27 18:14:08.000000000 +0100
+@@ -18,6 +18,7 @@
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ #include "xmms.h"
++#include "libxmms/rcc.h"
+ #include "libxmms/util.h"
+ #include "libxmms/titlestring.h"
+
+@@ -397,6 +398,8 @@
+ draw_playlist_window(TRUE);
+ draw_equalizer_window(TRUE);
+
++ xmms_rcc_prefswin_apply();
++
+ save_config();
+ }
+
+@@ -1105,6 +1108,11 @@
+ gtk_notebook_append_page(GTK_NOTEBOOK(prefswin_notebook), prefswin_fonts_vbox, gtk_label_new(_("Fonts")));
+
+ /*
++ * Coding Conversion page
++ */
++ xmms_rcc_prefswin_create(prefswin_notebook);
++
++ /*
+ * Title page
+ */
+ prefswin_title_vbox = gtk_vbox_new(FALSE, 0);
diff --git a/patches/xmms/xmms-ds-rusxmms-charset.patch b/patches/xmms/xmms-ds-rusxmms-charset.patch
new file mode 100644
index 0000000..670f9e3
--- /dev/null
+++ b/patches/xmms/xmms-ds-rusxmms-charset.patch
@@ -0,0 +1,87 @@
+diff -dPNur xmms-1.2.10/libxmms/charset.c xmms-1.2.10-new/libxmms/charset.c
+--- xmms-1.2.10/libxmms/charset.c 2005-08-10 03:20:03.000000000 +0200
++++ xmms-1.2.10-new/libxmms/charset.c 2005-08-10 02:54:12.000000000 +0200
+@@ -20,6 +20,7 @@
+ #include <langinfo.h>
+ #endif
+
++#include "rcc.h"
+ #include "charset.h"
+
+ char* xmms_charset_get_current(void)
+@@ -37,7 +38,7 @@
+ return charset;
+ }
+
+-static size_t utf16_strlen(const char *string)
++size_t utf16_strlen(const char *string)
+ {
+ size_t len = 0;
+
+@@ -78,7 +79,7 @@
+ /* + 1 for nul in case len == 1 */
+ outsize = ((insize + 3) & ~3) + 1;
+ out = g_malloc(outsize);
+- outleft = outsize - 1;
++ outleft = outsize - 2;
+ outptr = out;
+
+ retry:
+@@ -92,7 +93,7 @@
+ outsize = (outsize - 1) * 2 + 1;
+ out = g_realloc(out, outsize);
+ outptr = out + used;
+- outleft = outsize - 1 - used;
++ outleft = outsize - 2 - used;
+ goto retry;
+ case EINVAL:
+ break;
+@@ -110,6 +111,7 @@
+ }
+ }
+ *outptr = '\0';
++ *(outptr+1) = '\0';
+
+ iconv_close(cd);
+ return out;
+@@ -141,10 +143,14 @@
+
+ char* xmms_charset_from_latin1(const char *string)
+ {
++ char *cstring;
+ char *to = xmms_charset_get_current();
+
+ if (!string)
+ return NULL;
++
++ cstring = xmms_rcc_recode(XMMS_RCC_ID3, XMMS_RCC_CTYPE, string);
++ if (cstring) return cstring;
+
+ if (!strcmp(to, "UTF-8"))
+ return xmms_charset_convert(string, strlen(string), "ISO-8859-1", to);
+@@ -271,9 +277,14 @@
+
+ char* xmms_charset_from_latin1(const char *string)
+ {
++ char *cstring;
++
+ if (!string)
+ return NULL;
+
++ cstring = xmms_rcc_recode(XMMS_RCC_ID3, XMMS_RCC_CTYPE, string);
++ if (cstring) return cstring;
++
+ return g_strdup(string);
+ }
+
+diff -dPNur xmms-1.2.10/libxmms/charset.h xmms-1.2.10-new/libxmms/charset.h
+--- xmms-1.2.10/libxmms/charset.h 2005-08-10 03:20:03.000000000 +0200
++++ xmms-1.2.10-new/libxmms/charset.h 2005-08-10 01:41:01.000000000 +0200
+@@ -16,5 +16,7 @@
+ char* xmms_charset_from_utf16be(const unsigned char *string);
+ char* xmms_charset_from_latin1(const char *string);
+
++size_t utf16_strlen(const char *string);
++
+ #endif /* XMMS_CHARSET_H */
+
diff --git a/patches/xmms/xmms-ds-rusxmms.patch b/patches/xmms/xmms-ds-rusxmms.patch
new file mode 100644
index 0000000..6b9287f
--- /dev/null
+++ b/patches/xmms/xmms-ds-rusxmms.patch
@@ -0,0 +1,172 @@
+diff -dPNur xmms-1.2.11/libxmms/configure.in xmms-1.2.11-new/libxmms/configure.in
+--- xmms-1.2.11/libxmms/configure.in 2007-11-16 22:51:24.000000000 +0100
++++ xmms-1.2.11-new/libxmms/configure.in 2007-11-25 17:38:56.000000000 +0100
+@@ -57,6 +57,16 @@
+ AC_DEFINE([HAVE_CODESET],,[Define if nl_langinfo(CODESET) is available.])
+ fi
+
++AC_CHECK_LIB(rccgtk, rccUiInit,[
++ AC_CHECK_HEADERS(librcc.h librccui.h,[
++ LIBRCC_LIBS="-lrccgtk"
++ LIBRCC_INCLUDES=""
++ ],[
++ LIBRCC_LIBS=""
++ LIBRCC_INCLUDES=""
++])])
++AC_SUBST(LIBRCC_LIBS)
++AC_SUBST(LIBRCC_INCLUDES)
+
+ AC_OUTPUT([
+ Makefile
+diff -dPNur xmms-1.2.11/libxmms/Makefile.am xmms-1.2.11-new/libxmms/Makefile.am
+--- xmms-1.2.11/libxmms/Makefile.am 2004-04-04 10:51:20.000000000 +0200
++++ xmms-1.2.11-new/libxmms/Makefile.am 2007-11-25 17:38:56.000000000 +0100
+@@ -4,10 +4,11 @@
+ lib_LTLIBRARIES = libxmms.la
+
+ libxmms_la_LDFLAGS = -export-dynamic -version-info $(LIBXMMS_MAJOR_VERSION):$(LIBXMMS_MINOR_VERSION):$(LIBXMMS_MICRO_VERSION)
+-libxmms_la_LIBADD = @GTK_LIBS@ @POSIX_LIBS@
+-INCLUDES = @GTK_CFLAGS@ -I../intl -I..
++libxmms_la_LIBADD = @LIBRCC_LIBS@ @GTK_LIBS@ @POSIX_LIBS@
++INCLUDES = @LIBRCC_INCLUDES@ @GTK_CFLAGS@ -I../intl -I..
+
+ libxmms_la_SOURCES = \
++rcc.c rcc.h rcc_langs.h \
+ configfile.c configfile.h \
+ xmmsctrl.c xmmsctrl.h \
+ dirbrowser.c dirbrowser.h \
+diff -dPNur xmms-1.2.11/libxmms/titlestring.c xmms-1.2.11-new/libxmms/titlestring.c
+--- xmms-1.2.11/libxmms/titlestring.c 2006-07-24 00:11:51.000000000 +0200
++++ xmms-1.2.11-new/libxmms/titlestring.c 2007-11-25 17:39:21.000000000 +0100
+@@ -29,6 +29,7 @@
+ #include <string.h>
+ #include <ctype.h>
+
++#include "rcc.h"
+ #include "titlestring.h"
+ #include "../xmms/i18n.h"
+
+@@ -42,8 +43,9 @@
+ PAD_SIDE_RIGHT,
+ };
+
++#define xmms_vputstr(out, pstr, pad) xmms_charset_vputstr(out, pstr, pad, from, pflag, c)
+
+-static int xmms_vputstr(GString *output, char *pstr, struct padding *pad)
++static int xmms_orig_vputstr(GString *output, char *pstr, struct padding *pad)
+ {
+ int i;
+ /* Lenght of the string that is actually printed */
+@@ -83,6 +85,22 @@
+ return TRUE;
+ }
+
++static int xmms_charset_vputstr(GString *output, char *pstr, struct padding *pad, int from, gint pflag, char c) {
++ int res;
++ gchar *cstring = NULL;
++
++ if ((pflag&1)&&((c=='f')||(c=='F'))) {
++ cstring = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_CTYPE, pstr);
++ }
++ if ((pflag&2)&&((c=='a')||(c=='c')||(c=='g')||(c=='p')||(c=='t'))) {
++ cstring = xmms_rcc_recode((xmms_rcc_class)from, XMMS_RCC_CTYPE, pstr);
++ }
++
++ res = xmms_orig_vputstr(output, cstring?cstring:pstr, pad);
++ if (cstring) g_free(cstring);
++
++ return res;
++}
+
+ static int xmms_vputnum(GString *output, int ival, struct padding *pad)
+ {
+@@ -124,7 +142,7 @@
+ return TRUE;
+ }
+
+-static int parse_variable(char **fmt, GString *string, TitleInput *input)
++static int parse_variable(char **fmt, GString *string, TitleInput *input, int from, gint pflag)
+ {
+ struct padding padding;
+ char *ptr = *fmt;
+@@ -237,9 +255,33 @@
+ return exp;
+ }
+
++static int xmms_charset_analyze_fmt(gchar *fmt) {
++ int flag = 0;
++
++ if (!fmt) return 0;
++ for (;*fmt;fmt++) {
++ while ((*fmt != '%')&&(*fmt != 0)) fmt++;
++ if (!*fmt) break;
++ while ((*fmt == '-')||(*fmt == ' ')||(*fmt == '0')) fmt++;
++ while (*fmt >= '0' && *fmt <= '9') fmt++;
++ if (*fmt == '.') { fmt++; while (*fmt >= '0' && *fmt <= '9') fmt++; }
++ if ((*fmt=='a')||(*fmt=='c')||(*fmt=='g')||(*fmt=='p')||(*fmt=='t')) flag|=1;
++ if ((*fmt=='f')||(*fmt=='F')) flag|=2;
++ }
++
++ return flag;
++}
++
++gchar *xmms_charset_get_titlestring(gchar *fmt, TitleInput *input, int from);
+
+ char *xmms_get_titlestring(char *fmt, TitleInput *input)
+ {
++ return xmms_charset_get_titlestring(fmt, input, (xmms_rcc_class)-1);
++}
++
++gchar *xmms_charset_get_titlestring(gchar *fmt, TitleInput *input, int from) {
++ gint pflag;
++ gchar *cstring = NULL;
+ int f_output = 0;
+ GString *string;
+ char *strptr;
+@@ -249,12 +291,14 @@
+
+ string = g_string_new("");
+
++ pflag = (from == (xmms_rcc_class)-1)?0:xmms_charset_analyze_fmt(fmt);
++
+ while (*fmt)
+ {
+ if (*fmt == '%')
+ {
+ fmt++;
+- f_output += parse_variable(&fmt, string, input);
++ f_output += parse_variable(&fmt, string, input, from, pflag);
+ }
+ else
+ /* Normal character */
+@@ -271,6 +315,19 @@
+ /* Return the result */
+ strptr = string->str;
+ g_string_free(string, FALSE);
++
++ if (pflag<3) {
++ if (pflag&2)
++ cstring = xmms_rcc_recode(XMMS_RCC_FS, XMMS_RCC_CTYPE, strptr);
++ else
++ cstring = xmms_rcc_recode((xmms_rcc_class)from, XMMS_RCC_CTYPE, strptr);
++
++ if (cstring) {
++ g_free(strptr);
++ return cstring;
++ }
++ }
++
+ return strptr;
+ }
+
+diff -dPNur xmms-1.2.11/libxmms/titlestring.h xmms-1.2.11-new/libxmms/titlestring.h
+--- xmms-1.2.11/libxmms/titlestring.h 2005-05-15 02:01:20.000000000 +0200
++++ xmms-1.2.11-new/libxmms/titlestring.h 2007-11-25 17:38:56.000000000 +0100
+@@ -77,6 +77,7 @@
+ #endif
+
+ gchar *xmms_get_titlestring(gchar *fmt, TitleInput *input);
++gchar *xmms_charset_get_titlestring(gchar *fmt, TitleInput *input, int from);
+ GtkWidget* xmms_titlestring_descriptions(char* tags, int rows);
+
+ #ifdef __cplusplus
diff --git a/patches/xmms/xmms-ds-shade.patch b/patches/xmms/xmms-ds-shade.patch
new file mode 100644
index 0000000..41362df
--- /dev/null
+++ b/patches/xmms/xmms-ds-shade.patch
@@ -0,0 +1,194 @@
+diff -dPNur xmms-1.2.11/xmms/main.c xmms-1.2.11-new/xmms/main.c
+--- xmms-1.2.11/xmms/main.c 2007-11-25 01:10:52.000000000 +0100
++++ xmms-1.2.11-new/xmms/main.c 2007-11-25 01:11:13.000000000 +0100
+@@ -382,6 +382,8 @@
+
+ cfg.gentitle_format = NULL;
+
++ cfg.shade_font = NULL;
++
+ filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL);
+ cfgfile = xmms_cfg_open_file(filename);
+ if (cfgfile)
+@@ -481,6 +483,8 @@
+ }
+ xmms_cfg_read_string(cfgfile, "xmms", "generic_title_format", &cfg.gentitle_format);
+
++ xmms_cfg_read_string(cfgfile, "xmms", "shade_font", &cfg.shade_font);
++
+ xmms_cfg_free(cfgfile);
+ }
+
+@@ -519,6 +523,13 @@
+ if (cfg.eqpreset_extension == NULL)
+ cfg.eqpreset_extension = g_strdup("preset");
+
++ if (cfg.shade_font && strlen(cfg.shade_font) == 0) {
++ g_free(cfg.shade_font);
++ cfg.shade_font = NULL;
++ }
++ if (!cfg.shade_font)
++ cfg.shade_font = g_strdup("-misc-fixed-medium-r-*-*-7-*");
++
+ g_free(filename);
+ }
+
+@@ -677,6 +688,8 @@
+ }
+ xmms_cfg_write_string(cfgfile, "xmms", "generic_title_format", cfg.gentitle_format);
+
++ xmms_cfg_write_string(cfgfile, "xmms", "shade_font", cfg.shade_font);
++
+ xmms_cfg_write_file(cfgfile, filename);
+ xmms_cfg_free(cfgfile);
+
+diff -dPNur xmms-1.2.11/xmms/main.h xmms-1.2.11-new/xmms/main.h
+--- xmms-1.2.11/xmms/main.h 2006-07-16 15:40:04.000000000 +0200
++++ xmms-1.2.11-new/xmms/main.h 2007-11-25 01:12:55.000000000 +0100
+@@ -60,6 +60,7 @@
+ gint mouse_change;
+ gboolean playlist_transparent;
+ gchar *gentitle_format;
++ gchar *shade_font;
+ }
+ Config;
+
+diff -dPNur xmms-1.2.11/xmms/playlistwin.c xmms-1.2.11-new/xmms/playlistwin.c
+--- xmms-1.2.11/xmms/playlistwin.c 2007-11-16 22:51:30.000000000 +0100
++++ xmms-1.2.11-new/xmms/playlistwin.c 2007-11-25 01:11:13.000000000 +0100
+@@ -39,7 +39,8 @@
+ PButton *playlistwin_shade, *playlistwin_close;
+ static PlaylistSlider *playlistwin_slider = NULL;
+ static TextBox *playlistwin_time_min, *playlistwin_time_sec;
+-static TextBox *playlistwin_info, *playlistwin_sinfo;
++static TextBox *playlistwin_info;
++TextBox *playlistwin_sinfo;
+ static SButton *playlistwin_srew, *playlistwin_splay;
+ static SButton *playlistwin_spause, *playlistwin_sstop;
+ static SButton *playlistwin_sfwd, *playlistwin_seject;
+@@ -1882,6 +1883,7 @@
+ static void playlistwin_create_widgets(void)
+ {
+ playlistwin_sinfo = create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, 4, 4, cfg.playlist_width - 35, FALSE, SKIN_TEXT);
++ textbox_set_xfont(playlistwin_sinfo, cfg.mainwin_use_xfont, cfg.shade_font);
+ if (!cfg.playlist_shaded)
+ hide_widget(playlistwin_sinfo);
+ if (cfg.playlist_shaded)
+diff -dPNur xmms-1.2.11/xmms/prefswin.c xmms-1.2.11-new/xmms/prefswin.c
+--- xmms-1.2.11/xmms/prefswin.c 2007-11-25 01:10:52.000000000 +0100
++++ xmms-1.2.11-new/xmms/prefswin.c 2007-11-25 01:11:13.000000000 +0100
+@@ -35,6 +35,7 @@
+
+ static GtkWidget *prefswin_options_sd_entry, *prefswin_options_pbs_entry;
+
++static GtkWidget *prefswin_shade_font_entry, *prefswin_shade_font_browse;
+ static GtkWidget *prefswin_options_font_entry, *prefswin_options_font_browse;
+ static GtkWidget *prefswin_options_fontset, *prefswin_mainwin_font_entry;
+ static GtkWidget *prefswin_mainwin_xfont, *prefswin_options_mouse_spin;
+@@ -48,6 +49,7 @@
+ extern PButton *playlistwin_shade, *playlistwin_close, *equalizerwin_close;
+ extern PButton *mainwin_menubtn, *mainwin_minimize, *mainwin_shade, *mainwin_close;
+ extern TextBox *mainwin_info;
++extern TextBox *playlistwin_sinfo;
+ extern gboolean mainwin_focus, equalizerwin_focus, playlistwin_focus;
+
+ static gboolean is_opening = FALSE;
+@@ -343,11 +345,13 @@
+ gboolean show_wm_old = cfg.show_wm_decorations;
+ g_free(cfg.playlist_font);
+ g_free(cfg.mainwin_font);
++ g_free(cfg.shade_font);
+ g_free(cfg.gentitle_format);
+ prefswin_options_write_data();
+ cfg.snap_distance = CLAMP(atoi(gtk_entry_get_text(GTK_ENTRY(prefswin_options_sd_entry))), 0, 1000);
+ cfg.playlist_font = g_strdup(gtk_entry_get_text(GTK_ENTRY(prefswin_options_font_entry)));
+ cfg.mainwin_font = g_strdup(gtk_entry_get_text(GTK_ENTRY(prefswin_mainwin_font_entry)));
++ cfg.shade_font = g_strdup(gtk_entry_get_text(GTK_ENTRY(prefswin_shade_font_entry)));
+ cfg.gentitle_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(prefswin_title_entry)));
+ cfg.pause_between_songs_time = CLAMP(atoi(gtk_entry_get_text(GTK_ENTRY(prefswin_options_pbs_entry))), 0, 1000);
+ cfg.mouse_change = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(prefswin_options_mouse_spin));
+@@ -390,6 +394,7 @@
+ prefswin_toggle_wm_decorations();
+
+ textbox_set_xfont(mainwin_info, cfg.mainwin_use_xfont, cfg.mainwin_font);
++ textbox_set_xfont(playlistwin_sinfo, cfg.mainwin_use_xfont, cfg.shade_font);
+ playlist_list_set_font(cfg.playlist_font);
+ playlistwin_update_list();
+ mainwin_set_info_text();
+@@ -475,6 +480,34 @@
+ }
+ }
+
++void prefswin_shade_font_browse_ok(GtkWidget * w, gpointer data)
++{
++ GtkFontSelectionDialog *fontsel = GTK_FONT_SELECTION_DIALOG(data);
++ gchar *fontname;
++
++ fontname = gtk_font_selection_dialog_get_font_name(fontsel);
++
++ if (fontname)
++ gtk_entry_set_text(GTK_ENTRY(prefswin_shade_font_entry), fontname);
++
++ gtk_widget_destroy(GTK_WIDGET(fontsel));
++}
++
++void prefswin_shade_font_browse_cb(GtkWidget * w, gpointer data)
++{
++ static GtkWidget *fontsel;
++
++ if (fontsel != NULL)
++ return;
++
++ fontsel = gtk_font_selection_dialog_new(_("Select playlist font:"));
++ gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(fontsel), gtk_entry_get_text(GTK_ENTRY(prefswin_shade_font_entry)));
++ gtk_signal_connect(GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button), "clicked", GTK_SIGNAL_FUNC(prefswin_shade_font_browse_ok), fontsel);
++ gtk_signal_connect_object(GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(fontsel));
++ gtk_signal_connect(GTK_OBJECT(fontsel), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &fontsel);
++ gtk_widget_show(fontsel);
++}
++
+ void prefswin_gplugins_use_cb(GtkToggleButton * w, gpointer data)
+ {
+ gint sel;
+@@ -693,7 +726,10 @@
+ GtkWidget *prefswin_vplugins_box, *prefswin_vplugins_vbox;
+ GtkWidget *prefswin_vplugins_frame, *prefswin_vplugins_hbox;
+ GtkWidget *prefswin_vplugins_hbbox;
+-
++
++ GtkWidget *prefswin_fonts_shade_frame;
++ GtkWidget *options_font_shade_hbox, *options_font_shade_vbox;
++
+ GtkWidget *prefswin_options_frame, *prefswin_options_vbox;
+ GtkWidget *prefswin_mainwin_frame, *prefswin_mainwin_vbox;
+ GtkWidget *prefswin_fonts_vbox, *prefswin_fonts_playlist_frame;
+@@ -1105,6 +1141,21 @@
+ gtk_widget_set_usize(prefswin_mainwin_font_browse, 85, 17);
+ gtk_box_pack_start(GTK_BOX(prefswin_mainwin_font_hbox), prefswin_mainwin_font_browse, FALSE, TRUE, 0);
+
++ prefswin_fonts_shade_frame = gtk_frame_new(_("Shade"));
++ gtk_container_set_border_width(GTK_CONTAINER(prefswin_fonts_shade_frame), 5);
++ gtk_box_pack_start(GTK_BOX(prefswin_fonts_vbox), prefswin_fonts_shade_frame, FALSE, FALSE, 0);
++ options_font_shade_vbox = gtk_vbox_new(FALSE, 5);
++ gtk_container_border_width(GTK_CONTAINER(options_font_shade_vbox), 5);
++ gtk_container_add(GTK_CONTAINER(prefswin_fonts_shade_frame), options_font_shade_vbox);
++ options_font_shade_hbox = gtk_hbox_new(FALSE, 5);
++ gtk_box_pack_start_defaults(GTK_BOX(options_font_shade_vbox), options_font_shade_hbox);
++ prefswin_shade_font_entry = gtk_entry_new();
++ gtk_box_pack_start(GTK_BOX(options_font_shade_hbox), prefswin_shade_font_entry, TRUE, TRUE, 0);
++ prefswin_shade_font_browse = gtk_button_new_with_label(_("Browse"));
++ gtk_signal_connect(GTK_OBJECT(prefswin_shade_font_browse), "clicked", GTK_SIGNAL_FUNC(prefswin_shade_font_browse_cb), NULL);
++ gtk_widget_set_usize(prefswin_shade_font_browse, 85, 17);
++ gtk_box_pack_start(GTK_BOX(options_font_shade_hbox), prefswin_shade_font_browse, FALSE, TRUE, 0);
++
+ gtk_notebook_append_page(GTK_NOTEBOOK(prefswin_notebook), prefswin_fonts_vbox, gtk_label_new(_("Fonts")));
+
+ /*
+@@ -1390,6 +1441,7 @@
+
+ gtk_entry_set_text(GTK_ENTRY(prefswin_options_font_entry), cfg.playlist_font);
+ gtk_entry_set_text(GTK_ENTRY(prefswin_mainwin_font_entry), cfg.mainwin_font);
++ gtk_entry_set_text(GTK_ENTRY(prefswin_shade_font_entry), cfg.shade_font);
+ gtk_entry_set_text(GTK_ENTRY(prefswin_title_entry), cfg.gentitle_format);
+ sprintf(temp, "%u", cfg.snap_distance);
+ gtk_entry_set_text(GTK_ENTRY(prefswin_options_sd_entry), temp);
diff --git a/patches/xmms/xmms-ds-textbox.patch b/patches/xmms/xmms-ds-textbox.patch
new file mode 100644
index 0000000..8442606
--- /dev/null
+++ b/patches/xmms/xmms-ds-textbox.patch
@@ -0,0 +1,31 @@
+diff -dPNur xmms-1.2.10/xmms/textbox.c xmms-1.2.10-patched/xmms/textbox.c
+--- xmms-1.2.10/xmms/textbox.c 2001-12-01 18:00:51.000000000 +0100
++++ xmms-1.2.10-patched/xmms/textbox.c 2005-06-02 22:43:42.000000000 +0200
+@@ -166,6 +166,8 @@
+ GdkGC *gc, *maskgc;
+ GdkColor *c, pattern;
+ GdkBitmap *mask;
++ GdkWChar *wtext;
++ int len;
+
+ length = strlen(pixmaptext);
+
+@@ -192,6 +194,18 @@
+ tb->tb_pixmap_width, tb->tb_widget.height);
+ pattern.pixel = 1;
+ gdk_gc_set_foreground(maskgc, &pattern);
++ if (cfg.use_fontsets) {
++ wtext = g_malloc((length + 1) * sizeof(GdkWChar));
++ len = gdk_mbstowcs(wtext, pixmaptext, length + 1);
++ if (len == -1) {
++ for (len = 0; pixmaptext[len] != '\0'; len++)
++ wtext[len] = pixmaptext[len];
++ }
++ wtext[len] = L'\0';
++ gdk_draw_text_wc(mask,tb->tb_font, maskgc, 0, tb->tb_font->ascent, wtext, len );
++ g_free(wtext);
++ }
++ else
+ gdk_draw_text(mask, tb->tb_font, maskgc, 0,
+ tb->tb_font->ascent, pixmaptext, length);
+ gdk_gc_unref(maskgc);