changeset 95:b5a1b762f586 trunk

[svn] - xspf now uses url encoding for location entry.
author yaz
date Fri, 20 Oct 2006 00:59:45 -0700
parents 230d8b49db8b
children 63bde7ca7ad0
files ChangeLog src/xspf/Makefile src/xspf/urlencode.c src/xspf/urlencode.h src/xspf/xspf.c
diffstat 5 files changed, 190 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Oct 16 11:40:44 2006 -0700
+++ b/ChangeLog	Fri Oct 20 00:59:45 2006 -0700
@@ -1,3 +1,11 @@
+2006-10-16 18:40:44 +0000  Giacomo Lozito <james@develia.org>
+  revision [188]
+  - do not use a different DATA_DIR for audacious-plugins
+  trunk/configure.ac           |    2 +-
+  trunk/src/scrobbler/Makefile |    2 +-
+  2 files changed, 2 insertions(+), 2 deletions(-)
+
+
 2006-10-15 16:41:42 +0000  William Pitcock <nenolod@nenolod.net>
   revision [186]
   - workaround for GNOME VFS crash
--- a/src/xspf/Makefile	Mon Oct 16 11:40:44 2006 -0700
+++ b/src/xspf/Makefile	Fri Oct 20 00:59:45 2006 -0700
@@ -5,7 +5,7 @@
 
 LIBDIR = $(plugindir)/$(CONTAINER_PLUGIN_DIR)
 
-SOURCES = xspf.c base64.c
+SOURCES = xspf.c base64.c urlencode.c
 
 OBJECTS = ${SOURCES:.c=.o}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xspf/urlencode.c	Fri Oct 20 00:59:45 2006 -0700
@@ -0,0 +1,158 @@
+/* the original code was taken from wget-1.10.2 */
+
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <ctype.h>
+#include "urlencode.h"
+
+enum {
+  /* rfc1738 reserved chars + "$" and ",".  */
+  urlchr_reserved = 1,
+
+  /* rfc1738 unsafe chars, plus non-printables.  */
+  urlchr_unsafe   = 2
+};
+
+#define urlchr_test(c, mask) (urlchr_table[(unsigned char)(c)] & (mask))
+#define URL_RESERVED_CHAR(c) urlchr_test(c, urlchr_reserved)
+#define URL_UNSAFE_CHAR(c) urlchr_test(c, urlchr_unsafe)
+#define XNUM_TO_DIGIT(x) ("0123456789ABCDEF"[x] + 0)
+#define ISXDIGIT(x) (isxdigit((unsigned char)(x)))
+#define X2DIGITS_TO_NUM(h1, h2) ((XDIGIT_TO_NUM (h1) << 4) + XDIGIT_TO_NUM (h2))
+#define XDIGIT_TO_NUM(h) ((h) < 'A' ? (h) - '0' : toupper (h) - 'A' + 10)
+
+/* Shorthands for the table: */
+#define R  urlchr_reserved
+#define U  urlchr_unsafe
+#define RU R|U
+
+static const unsigned char urlchr_table[256] =
+{
+  U,  U,  U,  U,   U,  U,  U,  U,   /* NUL SOH STX ETX  EOT ENQ ACK BEL */
+  U,  U,  U,  U,   U,  U,  U,  U,   /* BS  HT  LF  VT   FF  CR  SO  SI  */
+  U,  U,  U,  U,   U,  U,  U,  U,   /* DLE DC1 DC2 DC3  DC4 NAK SYN ETB */
+  U,  U,  U,  U,   U,  U,  U,  U,   /* CAN EM  SUB ESC  FS  GS  RS  US  */
+  U,  0,  U, RU,   R,  U,  R,  0,   /* SP  !   "   #    $   %   &   '   */
+  0,  0,  0,  R,   R,  0,  0,  R,   /* (   )   *   +    ,   -   .   /   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* 0   1   2   3    4   5   6   7   */
+  0,  0, RU,  R,   U,  R,  U,  R,   /* 8   9   :   ;    <   =   >   ?   */
+ RU,  0,  0,  0,   0,  0,  0,  0,   /* @   A   B   C    D   E   F   G   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* H   I   J   K    L   M   N   O   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* P   Q   R   S    T   U   V   W   */
+  0,  0,  0, RU,   U, RU,  U,  0,   /* X   Y   Z   [    \   ]   ^   _   */
+  U,  0,  0,  0,   0,  0,  0,  0,   /* `   a   b   c    d   e   f   g   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* h   i   j   k    l   m   n   o   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* p   q   r   s    t   u   v   w   */
+  0,  0,  0,  U,   U,  U,  0,  U,   /* x   y   z   {    |   }   ~   DEL */
+
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+  U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
+};
+#undef R
+#undef U
+#undef RU
+
+/* URL-unescape the string S.
+
+   This is done by transforming the sequences "%HH" to the character
+   represented by the hexadecimal digits HH.  If % is not followed by
+   two hexadecimal digits, it is inserted literally.
+
+   The transformation is done in place.  If you need the original
+   string intact, make a copy before calling this function.  */
+
+char *
+xspf_url_decode (const char *s)
+{
+    char *copy = strdup(s);
+    char *t = copy;			/* t - tortoise */
+    char *h = copy;			/* h - hare     */
+
+    for (; *h; h++, t++)
+    {
+        if (*h != '%')
+        {
+        copychar:
+            *t = *h;
+        }
+        else
+        {
+            char c;
+            /* Do nothing if '%' is not followed by two hex digits. */
+            if (!h[1] || !h[2] || !(ISXDIGIT (h[1]) && ISXDIGIT (h[2])))
+                goto copychar;
+            c = X2DIGITS_TO_NUM (h[1], h[2]);
+            /* Don't unescape %00 because there is no way to insert it
+               into a C string without effectively truncating it. */
+            if (c == '\0')
+                goto copychar;
+            *t = c;
+            h += 2;
+        }
+    }
+    *t = '\0';
+    return copy;
+}
+
+/* The core of url_escape_* functions.  Escapes the characters that
+   match the provided mask in urlchr_table.
+
+   If ALLOW_PASSTHROUGH is non-zero, a string with no unsafe chars
+   will be returned unchanged.  If ALLOW_PASSTHROUGH is zero, a
+   freshly allocated string will be returned in all cases.  */
+
+static char *
+url_escape_1 (const char *s, unsigned char mask, int allow_passthrough)
+{
+  const char *p1;
+  char *p2, *newstr;
+  int newlen;
+  int addition = 0;
+
+  for (p1 = s; *p1; p1++)
+    if (urlchr_test (*p1, mask))
+      addition += 2;		/* Two more characters (hex digits) */
+
+  if (!addition)
+    return allow_passthrough ? (char *)s : strdup (s);
+
+  newlen = (p1 - s) + addition;
+  newstr = (char *)malloc (newlen + 1);
+
+  p1 = s;
+  p2 = newstr;
+  while (*p1)
+    {
+      /* Quote the characters that match the test mask. */
+      if (urlchr_test (*p1, mask))
+	{
+	  unsigned char c = *p1++;
+	  *p2++ = '%';
+	  *p2++ = XNUM_TO_DIGIT (c >> 4);
+	  *p2++ = XNUM_TO_DIGIT (c & 0xf);
+	}
+      else
+	*p2++ = *p1++;
+    }
+  g_return_if_fail (p2 - newstr == newlen);
+  *p2 = '\0';
+
+  return newstr;
+}
+
+/* URL-escape the unsafe characters (see urlchr_table) in a given
+   string, returning a freshly allocated string.  */
+
+char *
+xspf_url_encode (const char *s)
+{
+  return url_escape_1 (s, urlchr_unsafe, 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xspf/urlencode.h	Fri Oct 20 00:59:45 2006 -0700
@@ -0,0 +1,4 @@
+/* prototypes */
+
+char *xspf_url_decode(const char *url);
+char *xspf_url_encode(const char *path);
--- a/src/xspf/xspf.c	Mon Oct 16 11:40:44 2006 -0700
+++ b/src/xspf/xspf.c	Fri Oct 20 00:59:45 2006 -0700
@@ -45,6 +45,7 @@
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 
+#include "urlencode.h"
 #include "base64.h"
 
 #define TMP_BUF_LEN 128
@@ -61,11 +62,17 @@
 	// creator, album, title, duration, trackNum, annotation, image, 
 	for(nptr = track->children; nptr != NULL; nptr = nptr->next){
 		if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, "location")){
+			GError *err = NULL;
+			gchar *tmp = NULL;
 			xmlChar *str = xmlNodeGetContent(nptr);
-			location = g_locale_from_utf8(str,-1,NULL,NULL,NULL);
-			if(!location)
-				location = g_strdup(str);
+			tmp = g_locale_from_utf8(str, -1, NULL, NULL, &err); //for backward compatibility
+			if(err != NULL)
+				location = xspf_url_decode(str);
+			else
+				location = xspf_url_decode(tmp);
+
 			xmlFree(str);
+			g_free(tmp); g_free(err);
 		}
 		else if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, "creator")){
 			tuple->performer = (gchar *)xmlNodeGetContent(nptr);
@@ -126,7 +133,7 @@
 				xmlFree(str);
 				continue;
 			}
-			else if(!xmlStrcmp(rel, "b64filename")){
+			else if(!xmlStrcmp(rel, "b64filename")){ //for backward compatibility
 				gchar *b64str = NULL;
 				b64str = (gchar *)xmlNodeGetContent(nptr);
 				b64filename = g_malloc0(strlen(b64str)*3/4+1);
@@ -134,7 +141,6 @@
 				g_free(b64str);
 				continue;
 			}
-
 			xmlFree(rel);
 			rel = NULL;
 		}
@@ -234,23 +240,17 @@
 	{
 		PlaylistEntry *entry = PLAYLIST_ENTRY(node->data);
 		xmlNodePtr track, location;
-		gchar *utf_filename = NULL;
-		gboolean use_base64 = FALSE;
+		gchar *filename = NULL;
 
 		track = xmlNewNode(NULL, "track");
 		location = xmlNewNode(NULL, "location");
 
-		/* try locale encoding first */
-		utf_filename = g_locale_to_utf8(entry->filename, -1, NULL, NULL, NULL);
+		/* url encode file name */
+		filename = (gchar *)xspf_url_encode(entry->filename);
+		if(!g_utf8_validate(filename, -1, NULL))
+			continue;
 
-		if (!utf_filename) {
-			use_base64 = TRUE; /* filename isn't straightforward. */
-			/* if above fails, try to guess */
-			utf_filename = str_to_utf8(entry->filename);
-		}
-		if(!g_utf8_validate(utf_filename, -1, NULL))
-			continue;
-		xmlAddChild(location, xmlNewText(utf_filename));
+		xmlAddChild(location, xmlNewText(filename));
 		xmlAddChild(track, location);
 		xmlAddChild(tracklist, track);
 
@@ -367,22 +367,8 @@
 			}
 
 		}
-
-		if (use_base64 && entry->filename) {
-			gchar *b64str = NULL;
-			b64str = g_malloc0(strlen(entry->filename)*2);
-			to64frombits(b64str, entry->filename, strlen(entry->filename));
-			tmp = xmlNewNode(NULL, "meta");
-			xmlSetProp(tmp, "rel", "b64filename");
-			xmlAddChild(tmp, xmlNewText(b64str));
-			xmlAddChild(track, tmp);
-			g_free(b64str);
-			use_base64 = FALSE;
-		}
-
-		g_free(utf_filename);
-		utf_filename = NULL;
-
+		g_free(filename);
+		filename = NULL;
 	}
 
 	PLAYLIST_UNLOCK();