changeset 47:85d7e55b29d2 trunk

[svn] - redundant metadata has been removed. - weird filename will be handled in base64 encoding. - "comment" is replaced with "annotation".
author yaz
date Thu, 21 Sep 2006 07:08:55 -0700
parents 653288afa6e7
children 1021c6ec2ba4
files ChangeLog src/xspf/Makefile src/xspf/base64.c src/xspf/base64.h src/xspf/xspf.c
diffstat 5 files changed, 220 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Sep 21 04:16:52 2006 -0700
+++ b/ChangeLog	Thu Sep 21 07:08:55 2006 -0700
@@ -1,3 +1,12 @@
+2006-09-21 11:16:52 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [92]
+  - fix a $(BEEP_DEFINES) issue where -DDATA_DIR is wrong
+  
+
+  Changes:        Modified:
+  +1 -1           trunk/configure.ac  
+
+
 2006-09-21 11:03:13 +0000  William Pitcock <nenolod@nenolod.net>
   revision [90]
   - drop libmusicbrainz requirement
--- a/src/xspf/Makefile	Thu Sep 21 04:16:52 2006 -0700
+++ b/src/xspf/Makefile	Thu Sep 21 07:08:55 2006 -0700
@@ -5,7 +5,7 @@
 
 LIBDIR = $(plugindir)/$(CONTAINER_PLUGIN_DIR)
 
-SOURCES = xspf.c
+SOURCES = xspf.c base64.c
 
 OBJECTS = ${SOURCES:.c=.o}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xspf/base64.c	Thu Sep 21 07:08:55 2006 -0700
@@ -0,0 +1,114 @@
+/**
+ * \file base64.c
+ * \brief base-64 conversion routines.
+ *
+ * \author Eric S. Raymond <esr@snark.thyrsus.com>.
+ *
+ * For license terms, see the file COPYING.
+ *
+ * This base 64 encoding is defined in RFC2045 section 6.8,
+ * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
+ * scheme used here.
+ */
+#include <ctype.h>
+
+
+static const char base64digits[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define BAD	-1
+static const char base64val[] = {
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
+     52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
+     15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
+    BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
+     41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
+};
+#define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)
+
+/**
+ * \brief Raw bytes in quasi-big-endian order to base 64 string (NUL-terminated)
+ *
+ * \param[out]	out	A pointer to a char to hold the converted string
+ * \param[in]	in	String to convert
+ * \param[in]	inlen	Length of the string to be converted
+ */
+void to64frombits(unsigned char *out, const unsigned char *in, int inlen)
+{
+	for (; inlen >= 3; inlen -= 3)
+	{
+		*out++ = base64digits[in[0] >> 2];
+		*out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+		*out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+		*out++ = base64digits[in[2] & 0x3f];
+		in += 3;
+	}
+
+	if (inlen > 0)
+	{
+		unsigned char fragment;
+
+		*out++ = base64digits[in[0] >> 2];
+		fragment = (in[0] << 4) & 0x30;
+
+		if (inlen > 1)
+			fragment |= in[1] >> 4;
+
+		*out++ = base64digits[fragment];
+		*out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
+		*out++ = '=';
+	}
+	
+	*out = '\0';
+}
+
+/**
+ * \brief base 64 to raw bytes in quasi-big-endian order, returning count of bytes
+ *
+ * \param[out]	out	Where to save the converted string
+ * \param[in]	in	String to convert
+ * \return Number of converted bytes.
+ */
+int from64tobits(char *out, const char *in)
+{
+	int len = 0;
+	register unsigned char digit1, digit2, digit3, digit4;
+
+	if (in[0] == '+' && in[1] == ' ')
+		in += 2;
+	if (*in == '\r')
+		return(0);
+
+	do {
+		digit1 = in[0];
+		if (DECODE64(digit1) == BAD)
+			return(-1);
+		digit2 = in[1];
+		if (DECODE64(digit2) == BAD)
+			return(-1);
+		digit3 = in[2];
+		if (digit3 != '=' && DECODE64(digit3) == BAD)
+			return(-1);
+		digit4 = in[3];
+		if (digit4 != '=' && DECODE64(digit4) == BAD)
+			return(-1);
+		in += 4;
+		*out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4);
+		++len;
+		if (digit3 != '=')
+		{
+			*out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2);
+			++len;
+			if (digit4 != '=')
+			{
+				*out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4);
+				++len;
+			}
+		}
+	} while (*in && *in != '\r' && digit4 != '=');
+
+	return (len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xspf/base64.h	Thu Sep 21 07:08:55 2006 -0700
@@ -0,0 +1,28 @@
+/**
+ * \file base64.h
+ * \brief This file has all base64.c declarations
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * See COPYING for details.
+ */
+
+#ifndef BASE64_H_
+#define BASE64_H_
+
+void to64frombits(unsigned char*,const unsigned char*,int);
+int from64tobits(char*,const char*);
+
+#endif /* BASE64_H_ */
--- a/src/xspf/xspf.c	Thu Sep 21 04:16:52 2006 -0700
+++ b/src/xspf/xspf.c	Thu Sep 21 07:08:55 2006 -0700
@@ -45,12 +45,16 @@
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 
+#include "base64.h"
+
+#define TMP_BUF_LEN 128
+
 static void
 add_file(xmlNode *track, const gchar *filename, gint pos)
 {
 	xmlNode *nptr;
 	TitleInput *tuple;
-	gchar *locale_uri = NULL;
+	gchar *location = NULL, *b64filename = NULL, *locale_uri = NULL;
 
 	tuple = bmp_title_input_new();
 
@@ -58,16 +62,10 @@
 	for(nptr = track->children; nptr != NULL; nptr = nptr->next){
 		if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, "location")){
 			xmlChar *str = xmlNodeGetContent(nptr);
-			locale_uri = g_locale_from_utf8(str,-1,NULL,NULL,NULL);
-			if(!locale_uri){
-				/* try ISO-8859-1 for last resort */
-				locale_uri = g_convert(str, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL);
-			}
+			location = g_locale_from_utf8(str,-1,NULL,NULL,NULL);
+			if(!location)
+				location = g_strdup(str);
 			xmlFree(str);
-			if(locale_uri){
-				tuple->file_name = g_path_get_basename(locale_uri);
-				tuple->file_path = g_path_get_dirname(locale_uri);
-			}
 		}
 		else if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, "creator")){
 			tuple->performer = (gchar *)xmlNodeGetContent(nptr);
@@ -88,11 +86,15 @@
 			tuple->track_number = atol(str);
 			xmlFree(str);
 		}
+		else if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, "annotation")){
+			tuple->comment = (gchar *)xmlNodeGetContent(nptr);
+			continue;
+		}
 
 		//
 		// additional metadata
 		//
-		// year, date, genre, comment, file_ext, file_path, formatter
+		// year, date, genre, formatter, mtime, b64filename
 		//
 		else if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, "meta")){
 			xmlChar *rel = NULL;
@@ -113,30 +115,26 @@
 				tuple->genre = (gchar *)xmlNodeGetContent(nptr);
 				continue;
 			}
-			else if(!xmlStrcmp(rel, "comment")){
-				tuple->comment = (gchar *)xmlNodeGetContent(nptr);
-				continue;
-			}
-			else if(!xmlStrcmp(rel, "file_ext")){
-				tuple->file_ext = (gchar *)xmlNodeGetContent(nptr);
-				continue;
-			}
-			else if(!xmlStrcmp(rel, "file_path")){
-				tuple->file_path = (gchar *)xmlNodeGetContent(nptr);
-				continue;
-			}
 			else if(!xmlStrcmp(rel, "formatter")){
 				tuple->formatter = (gchar *)xmlNodeGetContent(nptr);
 				continue;
 			}
 			else if(!xmlStrcmp(rel, "mtime")){
-				xmlChar *str;
+				xmlChar *str = NULL;
 				str = xmlNodeGetContent(nptr);
 				tuple->mtime = (time_t)atoll(str);
-				if(str)
-					xmlFree(str);
+				xmlFree(str);
 				continue;
 			}
+			else if(!xmlStrcmp(rel, "b64filename")){
+				gchar *b64str = NULL;
+				b64str = (gchar *)xmlNodeGetContent(nptr);
+				b64filename = g_malloc0(strlen(b64str)*3/4+1);
+				from64tobits(b64filename, b64str);
+				g_free(b64str);
+				continue;
+			}
+
 			xmlFree(rel);
 			rel = NULL;
 		}
@@ -145,13 +143,20 @@
 	if (tuple->length == 0) {
 		tuple->length = -1;
 	}
-	// add file to playlist
-	playlist_load_ins_file_tuple(locale_uri, filename, pos, tuple);
-	pos++;
-	if(locale_uri) {
-		g_free(locale_uri);
-		locale_uri = NULL;
+
+	locale_uri = b64filename ? b64filename : location;
+
+	if(locale_uri){
+		tuple->file_name = g_path_get_basename(locale_uri);
+		tuple->file_path = g_path_get_dirname(locale_uri);
+		tuple->file_ext = g_strdup(strrchr(locale_uri, '.'));
+		// add file to playlist
+		playlist_load_ins_file_tuple(locale_uri, filename, pos, tuple);
+		pos++;
 	}
+
+	g_free(location); g_free(b64filename);
+	locale_uri = NULL; location = NULL; b64filename = NULL;
 }
 
 static void
@@ -223,6 +228,7 @@
 		PlaylistEntry *entry = PLAYLIST_ENTRY(node->data);
 		xmlNodePtr track, location;
 		gchar *utf_filename = NULL;
+		gboolean use_base64 = FALSE;
 
 		track = xmlNewNode(NULL, "track");
 		location = xmlNewNode(NULL, "location");
@@ -231,10 +237,10 @@
 		utf_filename = g_locale_to_utf8(entry->filename, -1, NULL, NULL, NULL);
 
 		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));
@@ -271,7 +277,7 @@
 			if (entry->tuple->length > 0)
 			{
 				gchar *str;
-				str = g_malloc(128); // XXX fix me.
+				str = g_malloc(TMP_BUF_LEN);
 				tmp = xmlNewNode(NULL, "duration");
 				sprintf(str, "%d", entry->tuple->length);
 				xmlAddChild(tmp, xmlNewText(str));
@@ -282,7 +288,7 @@
 			if (entry->tuple->track_number != 0)
 			{
 				gchar *str;
-				str = g_malloc(128); // XXX fix me.
+				str = g_malloc(TMP_BUF_LEN);
 				tmp = xmlNewNode(NULL, "trackNum");
 				sprintf(str, "%d", entry->tuple->track_number);
 				xmlAddChild(tmp, xmlNewText(str));
@@ -290,15 +296,23 @@
 				xmlAddChild(track, tmp);
 			}
 
+			if (entry->tuple->comment != NULL &&
+			    g_utf8_validate(entry->tuple->comment, -1, NULL))
+			{
+				tmp = xmlNewNode(NULL, "annotation");
+				xmlAddChild(tmp, xmlNewText(entry->tuple->comment));
+				xmlAddChild(track, tmp);
+			}
+
 			//
 			// additional metadata
 			//
-			// year, date, genre, comment, file_ext, file_path, formatter
+			// year, date, genre, formatter, mtime
 			//
 			if (entry->tuple->year != 0)
 			{
 				gchar *str;
-				str = g_malloc(128); // XXX fix me.
+				str = g_malloc(TMP_BUF_LEN);
 				tmp = xmlNewNode(NULL, "meta");
 				xmlSetProp(tmp, "rel", "year");
 				sprintf(str, "%d", entry->tuple->year);
@@ -325,33 +339,6 @@
 				xmlAddChild(track, tmp);
 			}
 
-			if (entry->tuple->comment != NULL &&
-			    g_utf8_validate(entry->tuple->comment, -1, NULL))
-			{
-				tmp = xmlNewNode(NULL, "meta");
-				xmlSetProp(tmp, "rel", "comment");
-				xmlAddChild(tmp, xmlNewText(entry->tuple->comment));
-				xmlAddChild(track, tmp);
-			}
-
-			if (entry->tuple->file_ext != NULL &&
-			    g_utf8_validate(entry->tuple->file_ext, -1, NULL))
-			{
-				tmp = xmlNewNode(NULL, "meta");
-				xmlSetProp(tmp, "rel", "file_ext");
-				xmlAddChild(tmp, xmlNewText(entry->tuple->file_ext));
-				xmlAddChild(track, tmp);
-			}
-
-			if (entry->tuple->file_path != NULL &&
-			    g_utf8_validate(entry->tuple->file_path, -1, NULL))
-			{
-				tmp = xmlNewNode(NULL, "meta");
-				xmlSetProp(tmp, "rel", "file_path");
-				xmlAddChild(tmp, xmlNewText(entry->tuple->file_path));
-				xmlAddChild(track, tmp);
-			}
-
 			if (entry->tuple->formatter != NULL &&
 			    g_utf8_validate(entry->tuple->formatter, -1, NULL))
 			{
@@ -363,20 +350,32 @@
 
 			if (entry->tuple->mtime) {
 				gchar *str;
-				str = g_malloc(128); // XXX fix me.
+				str = g_malloc(TMP_BUF_LEN);
 				tmp = xmlNewNode(NULL, "meta");
 				xmlSetProp(tmp, "rel", "mtime");
 				sprintf(str, "%ld", (long) entry->tuple->mtime);
 				xmlAddChild(tmp, xmlNewText(str));
 				xmlAddChild(track, tmp);
 				g_free(str);
-			}				
+			}
 
 		}
-		if(utf_filename) {
-			g_free(utf_filename);
-			utf_filename = NULL;
+
+		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;
+
 	}
 
 	xmlSaveFormatFile(filename, doc, 1);