Index: xmllexer.c
===================================================================
--- xmllexer.c	(revision 0)
+++ xmllexer.c	(revision 0)
@@ -0,0 +1,491 @@
+/*
+ *  Copyright (C) 2002-2003 the xine project
+ *
+ *  This file is part of xine, a free video player.
+ *
+ *  xine 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.
+ * 
+ *  xine 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
+ *
+ *  $Id: xmllexer.c,v 1.12 2006/06/20 00:35:08 dgp85 Exp $
+ *
+ */
+
+#define LOG_MODULE "xmllexer"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+
+#ifdef XINE_COMPILE
+#include "xineutils.h"
+#else
+#define lprintf(...)
+#define xine_xmalloc malloc
+#endif
+#include "xmllexer.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* private constants*/
+#define NORMAL       0  /* normal lex mode */
+#define DATA         1  /* data lex mode */
+
+/* private global variables */
+static const char * lexbuf;
+static int lexbuf_size = 0;
+static int lexbuf_pos  = 0;
+static int lex_mode    = NORMAL;
+static int in_comment  = 0;
+
+void lexer_init(const char * buf, int size) {
+  lexbuf      = buf;
+  lexbuf_size = size;
+  lexbuf_pos  = 0;
+  lex_mode    = NORMAL;
+  in_comment  = 0;
+
+  lprintf("buffer length %d\n", size);
+}
+
+int lexer_get_token(char * tok, int tok_size) {
+  int tok_pos = 0;
+  int state = 0;
+  char c;
+
+  if (tok) {
+    while ((tok_pos < tok_size) && (lexbuf_pos < lexbuf_size)) {
+      c = lexbuf[lexbuf_pos];
+      lprintf("c=%c, state=%d, in_comment=%d\n", c, state, in_comment);
+
+      if (lex_mode == NORMAL) {
+				/* normal mode */
+	switch (state) {
+	  /* init state */
+	case 0:
+	  switch (c) {
+	  case '\n':
+	  case '\r':
+	    state = 1;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case ' ':
+	  case '\t':
+	    state = 2;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case '<':
+	    state = 3;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case '>':
+	    state = 4;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case '/':
+	    if (!in_comment) 
+	      state = 5;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case '=':
+	    state = 6;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case '\"': /* " */
+	    state = 7;
+	    break;
+
+	  case '-':
+	    state = 10;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  case '?':
+	    state = 9;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+
+	  default:
+	    state = 100;
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    break;
+	  }
+	  lexbuf_pos++;
+	  break;
+
+	  /* end of line */
+	case 1:
+	  if (c == '\n' || (c == '\r')) {
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++;
+	  } else {
+	    tok[tok_pos] = '\0';
+	    return T_EOL;
+	  }
+	  break;
+
+	  /* T_SEPAR */
+	case 2:
+	  if (c == ' ' || (c == '\t')) {
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++;
+	  } else {
+	    tok[tok_pos] = '\0';
+	    return T_SEPAR;
+	  }
+	  break;
+
+	  /* T_M_START < or </ or <! or <? */
+	case 3:
+	  switch (c) {
+	  case '/':
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++; /* FIXME */
+	    tok[tok_pos] = '\0';
+	    return T_M_START_2;
+	    break;
+	  case '!':
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++;
+	    state = 8;
+	    break;
+	  case '?':
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++; /* FIXME */
+	    tok[tok_pos] = '\0';
+	    return T_TI_START;
+	    break;
+	  default:
+	    tok[tok_pos] = '\0';
+	    return T_M_START_1;
+	  }
+	  break;
+
+	  /* T_M_STOP_1 */
+	case 4:
+	  tok[tok_pos] = '\0';
+	  if (!in_comment)
+	    lex_mode = DATA;
+	  return T_M_STOP_1;
+	  break;
+
+	  /* T_M_STOP_2 */
+	case 5:
+	  if (c == '>') {
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++; /* FIXME */
+	    tok[tok_pos] = '\0';
+	    if (!in_comment)
+	      lex_mode = DATA;
+	    return T_M_STOP_2;
+	  } else {
+	    tok[tok_pos] = '\0';
+	    return T_ERROR;
+	  }
+	  break;
+
+	  /* T_EQUAL */
+	case 6:
+	  tok[tok_pos] = '\0';
+	  return T_EQUAL;
+	  break;
+
+	  /* T_STRING */
+	case 7:
+	  tok[tok_pos] = c;
+	  lexbuf_pos++;
+	  if (c == '\"') { /* " */
+	    tok[tok_pos] = '\0'; /* FIXME */
+	    return T_STRING;
+	  }
+	  tok_pos++;
+	  break;
+
+	  /* T_C_START or T_DOCTYPE_START */
+	case 8:
+	  switch (c) {
+	  case '-':
+	    lexbuf_pos++;
+	    if (lexbuf[lexbuf_pos] == '-')
+	      {
+		lexbuf_pos++;
+		tok[tok_pos++] = '-'; /* FIXME */
+		tok[tok_pos++] = '-';
+		tok[tok_pos] = '\0';
+		in_comment = 1;
+		return T_C_START;
+	      }
+	    break;
+	  case 'D':
+	    lexbuf_pos++;
+	    if (strncmp(lexbuf + lexbuf_pos, "OCTYPE", 6) == 0) {
+	      strncpy(tok + tok_pos, "DOCTYPE", 7); /* FIXME */
+	      lexbuf_pos += 6;
+	      return T_DOCTYPE_START;
+	    } else {
+	      return T_ERROR;
+	    }
+	    break;
+	  default:
+	    /* error */
+	    return T_ERROR;
+	  }
+	  break;
+
+	  /* T_TI_STOP */
+	case 9:
+	  if (c == '>') {
+	    tok[tok_pos] = c;
+	    lexbuf_pos++;
+	    tok_pos++; /* FIXME */
+	    tok[tok_pos] = '\0';
+	    return T_TI_STOP;
+	  } else {
+	    tok[tok_pos] = '\0';
+	    return T_ERROR;
+	  }
+	  break;
+
+	  /* -- */
+	case 10:
+	  switch (c) {
+	  case '-':
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	    state = 11;
+	    break;
+	  default:
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	    state = 100;
+	  }
+	  break;
+
+	  /* --> */
+	case 11:
+	  switch (c) {
+	  case '>':
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	    tok[tok_pos] = '\0'; /* FIX ME */
+	    if (strlen(tok) != 3) {
+	      tok[tok_pos - 3] = '\0';
+	      lexbuf_pos -= 3;
+	      return T_IDENT;
+	    } else {
+	      in_comment = 0;
+	      return T_C_STOP;
+	    }
+	    break;
+	  default:
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	    state = 100;
+	  }
+	  break;
+
+	  /* IDENT */
+	case 100:
+	  switch (c) {
+	  case '<':
+	  case '>':
+	  case '\\':
+	  case '\"': /* " */
+	  case ' ':
+	  case '\t':
+	  case '=':
+	  case '/':
+	    tok[tok_pos] = '\0';
+	    return T_IDENT;
+	    break;
+	  case '?':
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	    state = 9;
+	    break;
+	  case '-':
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	    state = 10;
+	    break;
+	  default:
+	    tok[tok_pos] = c;
+	    tok_pos++;
+	    lexbuf_pos++;
+	  }
+	  break;
+	default:
+	  lprintf("expected char \'%c\'\n", tok[tok_pos - 1]); /* FIX ME */
+	  return T_ERROR;
+	}
+      } else {
+				/* data mode, stop if char equal '<' */
+        switch (c)
+        {
+        case '<':
+	  tok[tok_pos] = '\0';
+	  lex_mode = NORMAL;
+	  return T_DATA;
+	default:
+	  tok[tok_pos] = c;
+	  tok_pos++;
+	  lexbuf_pos++;
+	}
+      }
+    }
+    lprintf ("loop done tok_pos = %d, tok_size=%d, lexbuf_pos=%d, lexbuf_size=%d\n", 
+	     tok_pos, tok_size, lexbuf_pos, lexbuf_size);
+
+    /* pb */
+    if (tok_pos >= tok_size) {
+      lprintf("token buffer is too little\n");
+    } else {
+      if (lexbuf_pos >= lexbuf_size) {
+				/* Terminate the current token */
+	tok[tok_pos] = '\0';
+	switch (state) {
+	case 0:
+	case 1:
+	case 2:
+	  return T_EOF;
+	  break;
+	case 3:
+	  return T_M_START_1;
+	  break;
+	case 4:
+	  return T_M_STOP_1;
+	  break;
+	case 5:
+	  return T_ERROR;
+	  break;
+	case 6:
+	  return T_EQUAL;
+	  break;
+	case 7:
+	  return T_STRING;
+	  break;
+	case 100:
+	  return T_DATA;
+	  break;
+	default:
+	  lprintf("unknown state, state=%d\n", state);
+	}
+      } else {
+	lprintf("abnormal end of buffer, state=%d\n", state);
+      }
+    }
+    return T_ERROR;
+  }
+  /* tok == null */
+  lprintf("token buffer is null\n");
+  return T_ERROR;
+}
+
+static struct {
+  char code;
+  unsigned char namelen;
+  char name[6];
+} lexer_entities[] = {
+  { '"',  4, "quot" },
+  { '&',  3, "amp" },
+  { '\'', 4, "apos" },
+  { '<',  2, "lt" },
+  { '>',  2, "gt" },
+  { '\0', 0, "" }
+};
+
+char *lexer_decode_entities (const char *tok)
+{
+  char *buf = xine_xmalloc (strlen (tok) + 1);
+  char *bp = buf;
+  char c;
+
+  while ((c = *tok++))
+  {
+    if (c != '&')
+      *bp++ = c;
+    else
+    {
+      /* parse the character entity (on failure, treat it as literal text) */
+      const char *tp = tok;
+      long i;
+
+      for (i = 0; lexer_entities[i].code; ++i)
+	if (!strncmp (lexer_entities[i].name, tok, lexer_entities[i].namelen)
+	    && tok[lexer_entities[i].namelen] == ';')
+	  break;
+      if (lexer_entities[i].code)
+      {
+        tok += lexer_entities[i].namelen + 1;
+	*bp++ = lexer_entities[i].code;
+	continue;
+      }
+
+      if (*tp++ != '#')
+      {
+        /* not a recognised name and not numeric */
+	*bp++ = '&';
+	continue;
+      }
+
+      /* entity is a number
+       * (note: strtol() allows "0x" prefix for hexadecimal, but we don't)
+       */
+      if (*tp == 'x' && tp[1] && tp[2] != 'x')
+	i = strtol (tp + 1, (char **)&tp, 16);
+      else
+	i = strtol (tp, (char **)&tp, 10);
+
+      if (i < 1 || i > 255 || *tp != ';')
+      {
+        /* out of range, or format error */
+	*bp++ = '&';
+	continue;
+      }
+
+      tok = tp + 1;
+      *bp++ = i;
+    }
+  }
+  *bp = 0;
+  return buf;
+}
Index: xmllexer.h
===================================================================
--- xmllexer.h	(revision 0)
+++ xmllexer.h	(revision 0)
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (C) 2002-2003 the xine project
+ *
+ *  This file is part of xine, a free video player.
+ *
+ *  xine 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.
+ *
+ *  xine 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
+ *
+ * $Id: xmllexer.h,v 1.7 2006/09/26 05:19:49 dgp85 Exp $
+ *
+ */
+
+/* xml lexer */
+#ifndef XML_LEXER_H
+#define XML_LEXER_H
+
+#ifndef XINE_PROTECTED
+#define XINE_PROTECTED
+#endif
+
+/* public constants */
+#define T_ERROR         -1   /* lexer error */
+#define T_EOF            0   /* end of file */
+#define T_EOL            1   /* end of line */
+#define T_SEPAR          2   /* separator ' ' '/t' '\n' '\r' */
+#define T_M_START_1      3   /* markup start < */
+#define T_M_START_2      4   /* markup start </ */
+#define T_M_STOP_1       5   /* markup stop > */
+#define T_M_STOP_2       6   /* markup stop /> */
+#define T_EQUAL          7   /* = */
+#define T_QUOTE          8   /* \" or \' */
+#define T_STRING         9   /* "string" */
+#define T_IDENT         10   /* identifier */
+#define T_DATA          11   /* data */
+#define T_C_START       12   /* <!-- */
+#define T_C_STOP        13   /* --> */
+#define T_TI_START      14   /* <? */
+#define T_TI_STOP       15   /* ?> */
+#define T_DOCTYPE_START 16   /* <!DOCTYPE */
+#define T_DOCTYPE_STOP  17   /* > */
+
+
+/* public functions */
+void lexer_init(const char * buf, int size) XINE_PROTECTED;
+int lexer_get_token(char * tok, int tok_size) XINE_PROTECTED;
+char *lexer_decode_entities (const char *tok) XINE_PROTECTED;
+
+#endif
Index: totem-pl-parser-private.h
===================================================================
--- totem-pl-parser-private.h	(revision 3908)
+++ totem-pl-parser-private.h	(working copy)
@@ -57,7 +57,7 @@
 int   totem_pl_parser_read_ini_line_int		(char **lines, const char *key);
 char *totem_pl_parser_read_ini_line_string_with_sep (char **lines, const char *key,
 						     gboolean dos_mode, const char *sep);
-char *totem_pl_resolve_url			(char *base, char *url);
+char *totem_pl_resolve_url			(const char *base, const char *url);
 char *totem_pl_parser_base_url			(const char *url);
 
 #ifndef TOTEM_PL_PARSER_MINI
Index: totem-pl-parser-wm.c
===================================================================
--- totem-pl-parser-wm.c	(revision 3908)
+++ totem-pl-parser-wm.c	(working copy)
@@ -29,8 +29,7 @@
 #include <libgnomevfs/gnome-vfs-mime-utils.h>
 
 #ifndef TOTEM_PL_PARSER_MINI
-#include <libxml/tree.h>
-#include <libxml/parser.h>
+#include "xmlparser.h"
 #include <gtk/gtk.h>
 #include <libgnomevfs/gnome-vfs.h>
 #include <libgnomevfs/gnome-vfs-mime.h>
@@ -128,55 +127,50 @@
 }
 
 static gboolean
-parse_asx_entry (TotemPlParser *parser, char *base, xmlDocPtr doc,
-		xmlNodePtr parent, const char *pl_title)
+parse_asx_entry (TotemPlParser *parser, const char *base, xml_node_t *parent, const char *pl_title)
 {
-	xmlNodePtr node;
+	xml_node_t *node;
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
-	xmlChar *title, *url;
-	char *fullpath = NULL;
+	const char *url;
+	char *title, *fullpath;
 
+	fullpath = NULL;
 	title = NULL;
 	url = NULL;
 
-	for (node = parent->children; node != NULL; node = node->next) {
+	for (node = parent->child; node != NULL; node = node->next) {
 		if (node->name == NULL)
 			continue;
 
 		/* ENTRY can only have one title node but multiple REFs */
-		if (g_ascii_strcasecmp ((char *)node->name, "ref") == 0
-				|| g_ascii_strcasecmp ((char *)node->name, "entryref") == 0) {
-			xmlChar *tmp;
+		if (g_ascii_strcasecmp (node->name, "ref") == 0
+				|| g_ascii_strcasecmp (node->name, "entryref") == 0) {
+			const char *tmp;
 
-			tmp = xmlGetProp (node, (const xmlChar *)"href");
+			tmp = xml_parser_get_property (node, "href");
 			if (tmp == NULL)
-				tmp = xmlGetProp (node, (const xmlChar *)"HREF");
+				tmp = xml_parser_get_property (node, "HREF");
 			if (tmp == NULL)
 				continue;
 			/* FIXME, should we prefer mms streams, or non-mms?
 			 * See bug #352559 */
 			if (url == NULL)
 				url = tmp;
-			else
-				xmlFree (tmp);
 
 			continue;
 		}
 
-		if (g_ascii_strcasecmp ((char *)node->name, "title") == 0)
-			title = xmlNodeListGetString(doc, node->children, 1);
+		if (g_ascii_strcasecmp (node->name, "title") == 0)
+			title = g_strdup (node->data);
 	}
 
 	if (url == NULL) {
-		if (title)
-			xmlFree (title);
+		g_free (title);
 		return TOTEM_PL_PARSER_RESULT_ERROR;
 	}
 
-	fullpath = totem_pl_resolve_url (base, (char *)url);
+	fullpath = totem_pl_resolve_url (base, url);
 
-	xmlFree (url);
-
 	/* .asx files can contain references to other .asx files */
 	retval = totem_pl_parser_parse_internal (parser, fullpath, NULL);
 	if (retval != TOTEM_PL_PARSER_RESULT_SUCCESS) {
@@ -185,60 +179,56 @@
 	}
 
 	g_free (fullpath);
-	if (title)
-		xmlFree (title);
+	g_free (title);
 
 	return retval;
 }
 
 static gboolean
-parse_asx_entries (TotemPlParser *parser, char *base, xmlDocPtr doc,
-		xmlNodePtr parent)
+parse_asx_entries (TotemPlParser *parser, const char *_base, xml_node_t *parent)
 {
-	xmlChar *title = NULL;
-	xmlNodePtr node;
+	char *title = NULL;
+	const char *newbase = NULL, *base = NULL;
+	xml_node_t *node;
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_ERROR;
-	xmlChar *newbase = NULL;
 
-	for (node = parent->children; node != NULL; node = node->next) {
+	base = _base;
+
+	for (node = parent->child; node != NULL; node = node->next) {
 		if (node->name == NULL)
 			continue;
 
-		if (g_ascii_strcasecmp ((char *)node->name, "title") == 0) {
-			title = xmlNodeListGetString(doc, node->children, 1);
+		if (g_ascii_strcasecmp (node->name, "title") == 0) {
+			title = g_strdup (node->data);
 		}
-		if (g_ascii_strcasecmp ((char *)node->name, "base") == 0) {
-			newbase = xmlGetProp (node, (const xmlChar *)"href");
+		if (g_ascii_strcasecmp (node->name, "base") == 0) {
+			newbase = xml_parser_get_property (node, "href");
 			if (newbase == NULL)
-				newbase = xmlGetProp (node, (const xmlChar *)"HREF");
+				newbase = xml_parser_get_property (node, "HREF");
 			if (newbase != NULL)
-				base = (char *)newbase;
+				base = newbase;
 		}
 
-		if (g_ascii_strcasecmp ((char *)node->name, "entry") == 0) {
-			/* Whee found an entry here, find the REF and TITLE */
-			if (parse_asx_entry (parser, base, doc, node, (char *)title) != FALSE)
+		if (g_ascii_strcasecmp (node->name, "entry") == 0) {
+			/* Whee! found an entry here, find the REF and TITLE */
+			if (parse_asx_entry (parser, base, node, (char *)title) != FALSE)
 				retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 		}
-		if (g_ascii_strcasecmp ((char *)node->name, "entryref") == 0) {
+		if (g_ascii_strcasecmp (node->name, "entryref") == 0) {
 			/* Found an entryref, give the parent instead of the
 			 * children to the parser */
-			if (parse_asx_entry (parser, base, doc, parent, (char *)title) != FALSE)
+			if (parse_asx_entry (parser, base, parent, (char *)title) != FALSE)
 				retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 		}
-		if (g_ascii_strcasecmp ((char *)node->name, "repeat") == 0) {
+		if (g_ascii_strcasecmp (node->name, "repeat") == 0) {
 			/* Repeat at the top-level */
-			if (parse_asx_entries (parser, base, doc, node) != FALSE)
+			if (parse_asx_entries (parser, base, node) != FALSE)
 				retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 		}
 	}
 
-	if (newbase)
-		xmlFree (newbase);
+	g_free (title);
 
-	if (title)
-		xmlFree (title);
-
 	return retval;
 }
 
@@ -246,36 +236,43 @@
 totem_pl_parser_add_asx (TotemPlParser *parser, const char *url,
 			 const char *base, gpointer data)
 {
-	xmlDocPtr doc;
-	xmlNodePtr node;
-	char *_base;
+	xml_node_t* doc;
+	char *_base, *contents;
+	int size;
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
 
 	if (data != NULL && totem_pl_parser_is_uri_list (data, strlen (data)) != FALSE) {
 		return totem_pl_parser_add_ram (parser, url, data);
 	}
 
-	doc = totem_pl_parser_parse_xml_file (url);
+	if (gnome_vfs_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
+		return TOTEM_PL_PARSER_RESULT_ERROR;
 
-	/* If the document has no root, or no name */
-	if(!doc || !doc->children || !doc->children->name) {
-		if (doc != NULL)
-			xmlFreeDoc(doc);
+	xml_parser_init (contents, size, XML_PARSER_CASE_INSENSITIVE);
+	if (xml_parser_build_tree (&doc) < 0) {
+		g_free (contents);
 		return TOTEM_PL_PARSER_RESULT_ERROR;
 	}
+	/* If the document has no name */
+	if (doc->name == NULL) {
+		g_free (contents);
+		xml_parser_free_tree (doc);
+		return TOTEM_PL_PARSER_RESULT_ERROR;
+	}
 
 	if (base == NULL) {
 		_base = totem_pl_parser_base_url (url);
 	} else {
-		_base =  g_strdup (base);
+		_base = g_strdup (base);
 	}
 
-	for (node = doc->children; node != NULL; node = node->next)
-		if (parse_asx_entries (parser, _base, doc, node) != FALSE)
-			retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
+	if (parse_asx_entries (parser, _base, doc) != FALSE)
+		retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 
 	g_free (_base);
-	xmlFreeDoc(doc);
+	g_free (contents);
+	xml_parser_free_tree (doc);
+
 	return retval;
 }
 
Index: xmlparser.c
===================================================================
--- xmlparser.c	(revision 0)
+++ xmlparser.c	(revision 0)
@@ -0,0 +1,593 @@
+/*
+ *  Copyright (C) 2002-2003 the xine project
+ *
+ *  This file is part of xine, a free video player.
+ *  This file is part of gxine, a free video player.
+ *
+ *  xine 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.
+ *
+ *  xine 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
+ *
+ *  $Id: xmlparser.c,v 1.15 2006/02/14 02:25:01 dsalt Exp $
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#define LOG_MODULE "xmlparser"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+
+#ifdef XINE_COMPILE
+#include "xineutils.h"
+#else
+#define lprintf(...)
+#define xine_xmalloc malloc
+#endif
+#include "xmllexer.h"
+#include "xmlparser.h"
+
+
+#define TOKEN_SIZE  4 * 1024
+#define DATA_SIZE   4 * 1024
+#define MAX_RECURSION 10
+
+/* private global variables */
+static int xml_parser_mode;
+
+/* private functions */
+
+static char * strtoupper(char * str) {
+  int i = 0;
+
+  while (str[i] != '\0') {
+    str[i] = (char)toupper((int)str[i]);
+    i++;
+  }
+  return str;
+}
+
+static xml_node_t * new_xml_node(void) {
+  xml_node_t * new_node;
+
+  new_node = (xml_node_t*) malloc(sizeof(xml_node_t));
+  new_node->name  = NULL;
+  new_node->data  = NULL;
+  new_node->props = NULL;
+  new_node->child = NULL;
+  new_node->next  = NULL;
+  return new_node;
+}
+
+static void free_xml_node(xml_node_t * node) {
+  free (node->name);
+  free (node->data);
+  free(node);
+}
+
+static xml_property_t * new_xml_property(void) {
+  xml_property_t * new_property;
+
+  new_property = (xml_property_t*) malloc(sizeof(xml_property_t));
+  new_property->name  = NULL;
+  new_property->value = NULL;
+  new_property->next  = NULL;
+  return new_property;
+}
+
+static void free_xml_property(xml_property_t * property) {
+  free (property->name);
+  free (property->value);
+  free(property);
+}
+
+void xml_parser_init(const char * buf, int size, int mode) {
+
+  lexer_init(buf, size);
+  xml_parser_mode = mode;
+}
+
+static void xml_parser_free_props(xml_property_t *current_property) {
+  if (current_property) {
+    if (!current_property->next) {
+      free_xml_property(current_property);
+    } else {
+      xml_parser_free_props(current_property->next);
+      free_xml_property(current_property);
+    }
+  }
+}
+
+static void xml_parser_free_tree_rec(xml_node_t *current_node, int free_next) {
+  lprintf("xml_parser_free_tree_rec: %s\n", current_node->name);
+
+  if (current_node) {
+    /* properties */
+    if (current_node->props) {
+      xml_parser_free_props(current_node->props);
+    }
+
+    /* child nodes */
+    if (current_node->child) {
+      lprintf("xml_parser_free_tree_rec: child\n");
+      xml_parser_free_tree_rec(current_node->child, 1);
+    }
+
+    /* next nodes */
+    if (free_next) {
+      xml_node_t *next_node = current_node->next;
+      xml_node_t *next_next_node;
+
+      while (next_node) {
+        next_next_node = next_node->next;
+        lprintf("xml_parser_free_tree_rec: next\n");
+        xml_parser_free_tree_rec(next_node, 0);
+        next_node = next_next_node;
+      }
+    }
+
+    free_xml_node(current_node);
+  }
+}
+
+void xml_parser_free_tree(xml_node_t *current_node) {
+  lprintf("xml_parser_free_tree\n");
+   xml_parser_free_tree_rec(current_node, 1);
+}
+
+#define STATE_IDLE    0
+#define STATE_NODE    1
+#define STATE_COMMENT 7
+
+static int xml_parser_get_node (xml_node_t *current_node, char *root_name, int rec) {
+  char tok[TOKEN_SIZE];
+  char property_name[TOKEN_SIZE];
+  char node_name[TOKEN_SIZE];
+  int state = STATE_IDLE;
+  int res = 0;
+  int parse_res;
+  int bypass_get_token = 0;
+  xml_node_t *subtree = NULL;
+  xml_node_t *current_subtree = NULL;
+  xml_property_t *current_property = NULL;
+  xml_property_t *properties = NULL;
+
+  if (rec < MAX_RECURSION) {
+
+    while ((bypass_get_token) || (res = lexer_get_token(tok, TOKEN_SIZE)) != T_ERROR) {
+      bypass_get_token = 0;
+      lprintf("info: %d - %d : '%s'\n", state, res, tok);
+
+      switch (state) {
+      case STATE_IDLE:
+	switch (res) {
+	case (T_EOL):
+	case (T_SEPAR):
+	  /* do nothing */
+	  break;
+	case (T_EOF):
+	  return 0; /* normal end */
+	  break;
+	case (T_M_START_1):
+	  state = STATE_NODE;
+	  break;
+	case (T_M_START_2):
+	  state = 3;
+	  break;
+	case (T_C_START):
+	  state = STATE_COMMENT;
+	  break;
+	case (T_TI_START):
+	  state = 8;
+	  break;
+	case (T_DOCTYPE_START):
+	  state = 9;
+	  break;
+	case (T_DATA):
+	  /* current data */
+	  if (current_node->data) {
+	    /* avoid a memory leak */
+	    free(current_node->data);
+	  }
+	  current_node->data = lexer_decode_entities(tok);
+	  lprintf("info: node data : %s\n", current_node->data);
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+
+      case STATE_NODE:
+	switch (res) {
+	case (T_IDENT):
+	  properties = NULL;
+	  current_property = NULL;
+
+	  /* save node name */
+	  if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) {
+	    strtoupper(tok);
+	  }
+	  strcpy(node_name, tok);
+	  state = 2;
+	  lprintf("info: current node name \"%s\"\n", node_name);
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+      case 2:
+	switch (res) {
+	case (T_EOL):
+	case (T_SEPAR):
+	  /* nothing */
+	  break;
+	case (T_M_STOP_1):
+	  /* new subtree */
+	  subtree = new_xml_node();
+
+	  /* set node name */
+	  subtree->name = strdup(node_name);
+
+	  /* set node propertys */
+	  subtree->props = properties;
+	  lprintf("info: rec %d new subtree %s\n", rec, node_name);
+	  parse_res = xml_parser_get_node(subtree, node_name, rec + 1);
+	  if (parse_res != 0) {
+	    return parse_res;
+	  }
+	  if (current_subtree == NULL) {
+	    current_node->child = subtree;
+	    current_subtree = subtree;
+	  } else {
+	    current_subtree->next = subtree;
+	    current_subtree = subtree;
+	  }
+	  state = STATE_IDLE;
+	  break;
+	case (T_M_STOP_2):
+	  /* new leaf */
+	  /* new subtree */
+	  subtree = new_xml_node();
+
+	  /* set node name */
+	  subtree->name = strdup (node_name);
+
+	  /* set node propertys */
+	  subtree->props = properties;
+
+	  lprintf("info: rec %d new subtree %s\n", rec, node_name);
+
+	  if (current_subtree == NULL) {
+	    current_node->child = subtree;
+	    current_subtree = subtree;
+	  } else {
+	    current_subtree->next = subtree;
+	    current_subtree = subtree; 
+	  }
+	  state = STATE_IDLE;
+	  break;
+	case (T_IDENT):
+	  /* save property name */
+	  if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) {
+	    strtoupper(tok);
+	  }
+	  strcpy(property_name, tok);
+	  state = 5;
+	  lprintf("info: current property name \"%s\"\n", property_name);
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+
+      case 3:
+	switch (res) {
+	case (T_IDENT):
+	  /* must be equal to root_name */
+	  if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) {
+	    strtoupper(tok);
+	  }
+	  if (strcmp(tok, root_name) == 0) {
+	    state = 4;
+	  } else {
+	    lprintf("error: xml struct, tok=%s, waited_tok=%s\n", tok, root_name);
+	    return -1;
+	  }
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+
+				/* > expected */
+      case 4:
+	switch (res) {
+	case (T_M_STOP_1):
+	  return 0;
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+
+				/* = or > or ident or separator expected */
+      case 5:
+	switch (res) {
+	case (T_EOL):
+	case (T_SEPAR):
+	  /* do nothing */
+	  break;
+	case (T_EQUAL):
+	  state = 6;
+	  break;
+	case (T_IDENT):
+	  bypass_get_token = 1; /* jump to state 2 without get a new token */
+	  state = 2;
+	  break;
+	case (T_M_STOP_1):
+	  /* add a new property without value */
+	  if (current_property == NULL) {
+	    properties = new_xml_property();
+	    current_property = properties;
+	  } else {
+	    current_property->next = new_xml_property();
+	    current_property = current_property->next;
+	  }
+	  current_property->name = strdup (property_name);
+	  lprintf("info: new property %s\n", current_property->name);
+	  bypass_get_token = 1; /* jump to state 2 without get a new token */
+	  state = 2;
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+
+				/* string or ident or separator expected */
+      case 6:
+	switch (res) {
+	case (T_EOL):
+	case (T_SEPAR):
+	  /* do nothing */
+	  break;
+	case (T_STRING):
+	case (T_IDENT):
+	  /* add a new property */
+	  if (current_property == NULL) {
+	    properties = new_xml_property();
+	    current_property = properties;
+	  } else {
+	    current_property->next = new_xml_property();
+	    current_property = current_property->next;
+	  }
+	  current_property->name = strdup(property_name);
+	  current_property->value = lexer_decode_entities(tok);
+	  lprintf("info: new property %s=%s\n", current_property->name, current_property->value);
+	  state = 2;
+	  break;
+	default:
+	  lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+	  return -1;
+	  break;
+	}
+	break;
+
+				/* --> expected */
+      case STATE_COMMENT:
+	switch (res) {
+	case (T_C_STOP):
+	  state = STATE_IDLE;
+	  break;
+	default:
+	  state = STATE_COMMENT;
+	  break;
+	}
+	break;
+
+				/* > expected */
+      case 8:
+	switch (res) {
+	case (T_TI_STOP):
+	  state = 0;
+	  break;
+	default:
+	  state = 8;
+	  break;
+	}
+	break;
+
+				/* ?> expected */
+      case 9:
+	switch (res) {
+	case (T_M_STOP_1):
+	  state = 0;
+	  break;
+	default:
+	  state = 9;
+	  break;
+	}
+	break;
+
+
+      default:
+	lprintf("error: unknown parser state, state=%d\n", state);
+	return -1;
+      }
+    }
+    /* lex error */
+    lprintf("error: lexer error\n");
+    return -1;
+  } else {
+    /* max recursion */
+    lprintf("error: max recursion\n");
+    return -1;
+  }
+}
+
+int xml_parser_build_tree(xml_node_t **root_node) {
+  xml_node_t *tmp_node;
+  int res;
+
+  tmp_node = new_xml_node();
+  res = xml_parser_get_node(tmp_node, "", 0);
+  if ((tmp_node->child) && (!tmp_node->child->next)) {
+    *root_node = tmp_node->child;
+    free_xml_node(tmp_node);
+    res = 0;
+  } else {
+    lprintf("error: xml struct\n");
+    xml_parser_free_tree(tmp_node);
+    res = -1;
+  }
+  return res;
+}
+
+char *xml_parser_get_property (const xml_node_t *node, const char *name) {
+
+  xml_property_t *prop;
+
+  prop = node->props;
+  while (prop) {
+
+    lprintf ("looking for %s in %s\n", name, prop->name);
+
+    if (!strcasecmp (prop->name, name)) {
+      lprintf ("found it. value=%s\n", prop->value);
+      return prop->value;
+    }
+
+    prop = prop->next;
+  }
+
+  return NULL;
+}
+
+int xml_parser_get_property_int (const xml_node_t *node, const char *name, 
+				 int def_value) {
+
+  char *v;
+  int   ret;
+
+  v = xml_parser_get_property (node, name);
+
+  if (!v)
+    return def_value;
+
+  if (sscanf (v, "%d", &ret) != 1)
+    return def_value;
+  else
+    return ret;
+}
+
+int xml_parser_get_property_bool (const xml_node_t *node, const char *name, 
+				  int def_value) {
+
+  char *v;
+
+  v = xml_parser_get_property (node, name);
+
+  if (!v)
+    return def_value;
+
+  return !strcasecmp (v, "true");
+}
+
+static int xml_escape_string_internal (char *buf, const char *s,
+				       xml_escape_quote_t quote_type)
+{
+  int c, length = 0;
+  int sl = buf ? 8 : 0;
+  /* calculate max required buffer size */
+  while ((c = *s++ & 0xFF))
+    switch (c)
+    {
+    case '"':  if (quote_type != XML_ESCAPE_DOUBLE_QUOTE) goto literal;
+	       length += snprintf (buf + length, sl, "&quot;"); break;
+    case '\'': if (quote_type != XML_ESCAPE_SINGLE_QUOTE) goto literal;
+	       length += snprintf (buf + length, sl, "&apos;"); break;
+    case '&':  length += snprintf (buf + length, sl, "&amp;");  break;
+    case '<':  length += snprintf (buf + length, sl, "&lt;");   break;
+    case '>':  length += snprintf (buf + length, sl, "&gt;");   break;
+    case 127:  length += snprintf (buf + length, sl, "&#127;"); break;
+    case '\t':
+    case '\n':
+      literal: if (buf)	buf[length] = c; ++length; break;
+    default:   if (c >= ' ') goto literal;
+	       length += snprintf (buf + length, sl, "&#%d;", c); break;
+    }
+  if (buf)
+    buf[length] = 0;
+  return length + 1;
+}
+
+char *xml_escape_string (const char *s, xml_escape_quote_t quote_type)
+{
+  char *buf = xine_xmalloc (xml_escape_string_internal (NULL, s, quote_type));
+  return buf ? (xml_escape_string_internal (buf, s, quote_type), buf) : NULL;
+}
+
+static void xml_parser_dump_node (const xml_node_t *node, int indent) {
+
+  xml_property_t *p;
+  xml_node_t     *n;
+  int             l;
+
+  printf ("%*s<%s ", indent, "", node->name);
+
+  l = strlen (node->name);
+
+  p = node->props;
+  while (p) {
+    char *value = xml_escape_string (p->value, XML_ESCAPE_SINGLE_QUOTE);
+    printf ("%s='%s'", p->name, value);
+    free (value);
+    p = p->next;
+    if (p) {
+      printf ("\n%*s", indent+2+l, "");
+    }
+  }
+  printf (">\n");
+
+  n = node->child;
+  while (n) {
+
+    xml_parser_dump_node (n, indent+2);
+
+    n = n->next;
+  }
+
+  printf ("%*s</%s>\n", indent, "", node->name);
+}
+
+void xml_parser_dump_tree (const xml_node_t *node) {
+  xml_parser_dump_node (node, 0);
+}
Index: xmlparser.h
===================================================================
--- xmlparser.h	(revision 0)
+++ xmlparser.h	(revision 0)
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (C) 2002-2003 the xine project
+ *
+ *  This file is part of xine, a free video player.
+ *
+ *  xine 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.
+ *
+ *  xine 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
+ *
+ *  $Id: xmlparser.h,v 1.5 2006/09/26 05:19:49 dgp85 Exp $
+ *
+ */
+#ifndef XML_PARSER_H
+#define XML_PARSER_H
+
+#ifndef XINE_PROTECTED
+#define XINE_PROTECTED
+#endif
+
+/* parser modes */
+#define XML_PARSER_CASE_INSENSITIVE  0
+#define XML_PARSER_CASE_SENSITIVE    1
+
+/* return codes */
+#define XML_PARSER_OK                0
+#define XML_PARSER_ERROR             1
+
+
+/* xml property */
+typedef struct xml_property_s {
+	char *name;
+	char *value;
+	struct xml_property_s *next;
+} xml_property_t;
+
+/* xml node */
+typedef struct xml_node_s {
+	char *name;
+	char *data;
+	struct xml_property_s *props;
+	struct xml_node_s *child;
+	struct xml_node_s *next;
+} xml_node_t;
+
+void xml_parser_init(const char * buf, int size, int mode) XINE_PROTECTED;
+
+int xml_parser_build_tree(xml_node_t **root_node) XINE_PROTECTED;
+
+void xml_parser_free_tree(xml_node_t *root_node) XINE_PROTECTED;
+
+char *xml_parser_get_property (const xml_node_t *node, const char *name) XINE_PROTECTED;
+int   xml_parser_get_property_int (const xml_node_t *node, const char *name, 
+				   int def_value) XINE_PROTECTED;
+int xml_parser_get_property_bool (const xml_node_t *node, const char *name, 
+				  int def_value) XINE_PROTECTED;
+
+/* for output:
+ * returns an escaped string (free() it when done)
+ * input must be in ASCII or UTF-8
+ */
+
+typedef enum {
+  XML_ESCAPE_NO_QUOTE,
+  XML_ESCAPE_SINGLE_QUOTE,
+  XML_ESCAPE_DOUBLE_QUOTE
+} xml_escape_quote_t;
+char *xml_escape_string (const char *s, xml_escape_quote_t quote_type) XINE_PROTECTED;
+
+/* for debugging purposes: dump read-in xml tree in a nicely
+ * indented fashion
+ */
+
+void xml_parser_dump_tree (const xml_node_t *node) XINE_PROTECTED;
+
+#endif
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 3908)
+++ Makefile.am	(working copy)
@@ -64,7 +64,9 @@
 	totem-pl-parser-wm.c			\
 	totem-pl-parser-wm.h			\
 	totem-pl-parser-xspf.c			\
-	totem-pl-parser-xspf.h
+	totem-pl-parser-xspf.h			\
+	xmlparser.h xmlparser.c			\
+	xmllexer.h xmllexer.c
 
 libtotem_plparser_la_CPPFLAGS = \
 	-I$(top_srcdir)				\
Index: totem-pl-parser.c
===================================================================
--- totem-pl-parser.c	(revision 3912)
+++ totem-pl-parser.c	(working copy)
@@ -798,7 +798,7 @@
 }
 
 char *
-totem_pl_resolve_url (char *base, char *url)
+totem_pl_resolve_url (const char *base, const char *url)
 {
 	GnomeVFSURI *base_uri, *new;
 	char *resolved;
@@ -1085,10 +1085,7 @@
 		return TOTEM_PL_PARSER_RESULT_SUCCESS;
 	}
 
-	if (ret == TOTEM_PL_PARSER_RESULT_SUCCESS)
-		return TOTEM_PL_PARSER_RESULT_SUCCESS;
-	else
-		return TOTEM_PL_PARSER_RESULT_UNHANDLED;
+	return ret;
 }
 
 TotemPlParserResult
